模板方法模式是“四人帮”(译者注:Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides)所著《Design Patterns book》一书中所描述的23种设计模式其中的一种,该模式旨在:
“Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.
TemplateMethod lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure”。
即模板方法定义一个算法的架构,并将某些步骤推迟到子类中实现。模板方法允许子类在不改变算法架构的情况下,重新定义算法中某些步骤。
为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行。在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容。
模板方法可以应用在上述场景中:将工作流系统的4个核心任务封装到抽象类当中,如果任务可以被自定义,则将可自定义的任务推迟到子类中实现。
代码实现:
01 |
/** |
02 |
* Abstract Workflow system |
03 |
*/ |
04 |
abstract class WorkflowManager2{ |
05 |
06 |
public void doTask1(){ |
07 |
08 |
System.out.println( "Doing Task1..." ); |
09 |
10 |
} |
11 |
12 |
public abstract void doTask2(); |
13 |
14 |
public abstract void doTask3(); |
15 |
16 |
public void doTask4(){ |
17 |
18 |
System.out.println( "Doing Task4..." ); |
19 |
20 |
} |
21 |
22 |
} |
23 |
24 |
/** |
25 |
* One of the extensions of the abstract workflow system |
26 |
*/ |
27 |
class WorkflowManager2Impl1 extends WorkflowManager2{ |
28 |
29 |
@Override |
30 |
public void doTask2(){ |
31 |
32 |
System.out.println( "Doing Task2.1..." ); |
33 |
34 |
} |
35 |
36 |
@Override |
37 |
public void doTask3(){ |
38 |
39 |
System.out.println( "Doing Task3.1..." ); |
40 |
41 |
} |
42 |
43 |
} |
44 |
45 |
/** |
46 |
* Other extension of the abstract workflow system |
47 |
*/ |
48 |
class WorkflowManager2Impl2 extends WorkflowManager2{ |
49 |
50 |
@Override |
51 |
public void doTask2(){ |
52 |
53 |
System.out.println( "Doing Task2.2..." ); |
54 |
55 |
} |
56 |
57 |
@Override |
58 |
public void doTask3(){ |
59 |
60 |
System.out.println( "Doing Task3.2..." ); |
61 |
62 |
} |
63 |
64 |
} |
我们来看看工作流系统如何使用:
01 |
public class TemplateMethodPattern { |
02 |
03 |
public static void main(String[] args) { |
04 |
05 |
initiateWorkFlow( new WorkflowManager2Impl1()); |
06 |
07 |
initiateWorkFlow( new WorkflowManager2Impl2()); |
08 |
09 |
} |
10 |
11 |
static void initiateWorkFlow(WorkflowManager2 workflowMgr){ |
12 |
13 |
System.out.println( "Starting the workflow ... the old way" ); |
14 |
15 |
workflowMgr.doTask1(); |
16 |
17 |
workflowMgr.doTask2(); |
18 |
19 |
workflowMgr.doTask3(); |
20 |
21 |
workflowMgr.doTask4(); |
22 |
23 |
} |
24 |
25 |
} |
输出如下所示:
01 |
Starting the workflow ... the old way |
02 |
03 |
Doing Task1... |
04 |
05 |
Doing Task2. 1 ... |
06 |
07 |
Doing Task3. 1 ... |
08 |
09 |
Doing Task4... |
10 |
11 |
Starting the workflow ... the old way |
12 |
13 |
Doing Task1... |
14 |
15 |
Doing Task2. 2 ... |
16 |
17 |
Doing Task3. 2 ... |
18 |
19 |
Doing Task4... |
目前为止一切顺利。但是本篇博客的主要关注点不是模板方法模式,而是如何利用Java 8的Lambda表达式和默认方法实现模板方法模式。我之前已经说过,接口只有在只声明了一个抽象方法的前提下,才可以使用Lambda表达式。这个规则在本篇的例子中应这样解释:WorkflowManager2只能有一个抽象或者说自定义的任务。
如果你仍然对Java 8中的Lambda表达式和默认方法感到疑惑,可以在深入研究之前,花一点时间看一看Lambda表达式和默认方法这两篇文章。
我们可以利用带有默认方法的接口替代抽象类,所以我们的新工作流系统如下所示:
01 |
interface WorkflowManager{ |
02 |
03 |
public default void doTask1(){ |
04 |
05 |
System.out.println( "Doing Task1..." ); |
06 |
07 |
} |
08 |
09 |
public void doTask2(); |
10 |
11 |
public default void doTask3(){ |
12 |
13 |
System.out.println( "Doing Task3..." ); |
14 |
15 |
} |
16 |
17 |
public default void doTask4(){ |
18 |
19 |
System.out.println( "Doing Task4..." ); |
20 |
21 |
} |
22 |
23 |
} |
现在我们的工作流系统带有一个可自定义的任务2,我们继续往下走,利用Lambda表达式处理初始化工作:
01 |
public class TemplateMethodPatternLambda { |
02 |
03 |
public static void main(String[] args) { |
04 |
05 |
/** |
06 |
* Using lambda expression to create different |
07 |
* implementation of the abstract workflow |
08 |
*/ |
09 |
initiateWorkFlow(()->System.out.println( "Doing Task2.1..." )); |
10 |
11 |
initiateWorkFlow(()->System.out.println( "Doing Task2.2..." )); |
12 |
13 |
initiateWorkFlow(()->System.out.println( "Doing Task2.3..." )); |
14 |
15 |
} |
16 |
17 |
static void initiateWorkFlow(WorkflowManager workflowMgr){ |
18 |
19 |
System.out.println( "Starting the workflow ..." ); |
20 |
21 |
workflowMgr.doTask1(); |
22 |
23 |
workflowMgr.doTask2(); |
24 |
25 |
workflowMgr.doTask3(); |
26 |
27 |
workflowMgr.doTask4(); |
28 |
29 |
} |
30 |
31 |
} |
这就是一个Lambda表达式应用在模板方法模式中的例子。