我們思考這麼一種場景,課堂上老師在黑闆即興出幾道題,學生在下面在手抄黑闆上的題目,這個時候前面的同學可能能抄對題目,但後面的同學可能因為太遠看不清老師寫的字,或者說老師寫錯了一個資料要修改的時候,所有學生都要跟着改一遍。連題目都抄錯的同學,怎麼可能做對題呢?不是同樣的标準,怎麼評判學生的成績呢?
但在正式的考試中,老師并不會在黑闆上出題學生抄題目答題,而是老師會發給每個同學一份事先出好的試卷,這樣在題目上所有同學拿到的都是同一份試卷,學生隻負責寫上自己的答案,我們也就有了同樣的标準來評判每個人的成績水準。我們将試卷抽象成公共類,每個學生的試卷繼承這個試卷公共類,隻在自己類裡實作“答案”即可。可見其實模闆方法模式的類結構很簡單。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SNxETO2cDO2QTMtczM2YTNxMDMwQjM5AjNxAjMtYDNyAzM28CX5AjNxAjMvwlN0IDMzYzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
我們根據上面所舉的例子,來具體實作模闆方法模式。
首先是抽象公共類:
1 package day_23_templateMethod;
2
3 /**
4 * 試卷的公共類,也就是老師出的試卷
5 * @author turbo
6 *
7 * 2016年9月24日
8 */
9 public abstract class AbstractClass {
10
11 /**
12 * 模闆方法1。所有學生都用一個模闆,即所有學生都繼承此題目1。
13 */
14 public void templateMethod1(){
15 System.out.println("模闆方法1(題目1)");
16 System.out.println("答案" + answer1());
17 }
18
19 /**
20 * 模闆方法2。所有學生都用一個模闆,即所有學生都繼承此題目2。
21 */
22 public void templateMethod2(){
23 System.out.println("模闆方法2(題目2)");
24 System.out.println("答案" + answer2());
25 }
26
27 /**
28 * 抽象行為1,由子類去具體實作。在這裡就是具體1的題目答案由每個學生自己作答。
29 * @return
30 */
31 protected abstract String answer1();
32
33 /**
34 * 抽象行為2,由子類去具體實作。在這裡就是具體的題目2答案由每個學生自己作答。
35 * @return
36 */
37 protected abstract String answer2();
38
39
40 }
學生A和學生B拿到試卷(繼承模闆方法),兩個學生寫出自己的答案(實作抽象行為):
1 package day_23_templateMethod;
2
3 /**
4 * 實作模闆方法中所要調用的抽象方法。在這裡是試卷1
5 * @author turbo
6 *
7 * 2016年9月24日
8 */
9 public class ConcreteClassA extends AbstractClass {
10
11 /**
12 * @param string
13 */
14 public ConcreteClassA(String string) {
15 System.out.println(string);
16 }
17
18 /* (non-Javadoc)
19 * @see day_23_templateMethod.AbstractClass#answer1()
20 */
21 @Override
22 protected String answer1() {
23 return "A"; //選擇答案A
24 }
25
26 /* (non-Javadoc)
27 * @see day_23_templateMethod.AbstractClass#answer2()
28 */
29 @Override
30 protected String answer2() {
31 return "B"; //選擇答案B
32 }
33
34 }
1 package day_23_templateMethod;
2
3 /**
4 * 實作模闆方法中所要調用的抽象方法。在這裡是試卷2
5 * @author turbo
6 *
7 * 2016年9月24日
8 */
9 public class ConcreteClassB extends AbstractClass {
10
11 /**
12 * @param string
13 */
14 public ConcreteClassB(String string) {
15 System.out.println(string);
16 }
17
18 /* (non-Javadoc)
19 * @see day_23_templateMethod.AbstractClass#answer1()
20 */
21 @Override
22 protected String answer1() {
23 return "C"; //答案選C
24 }
25
26 /* (non-Javadoc)
27 * @see day_23_templateMethod.AbstractClass#answer2()
28 */
29 @Override
30 protected String answer2() {
31 return "D"; //答案選D
32 }
33
34 }
用戶端測試代碼:
1 package day_23_templateMethod;
2
3 /**
4 * @author turbo
5 *
6 * 2016年9月24日
7 */
8 public class Main {
9
10 /**
11 * @param args
12 */
13 public static void main(String[] args) {
14 ConcreteClassA studentA = new ConcreteClassA("學生A作答情況");
15 studentA.templateMethod1();
16 studentA.templateMethod2();
17
18 ConcreteClassB studentB = new ConcreteClassB("學生B作答情況");
19 studentB.templateMethod1();
20 studentB.templateMethod2();
21 }
22
23 }
在敲完實作模闆方法模式代碼後,我們給模闆方法模式一個定義:定義一個操作中的算法的骨架,而将一些步驟延遲到子類中。模闆方法模式使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。當我們要完成在某一細節層次一緻的一個過程或一系列步驟,但其個别步驟在更詳細的層次上的實作可能不同時,我們通常考慮用模闆方法模式來處理。——《大話資料結構》
不積跬步,無以至千裡;不積小流,無以成江海。