我们思考这么一种场景,课堂上老师在黑板即兴出几道题,学生在下面在手抄黑板上的题目,这个时候前面的同学可能能抄对题目,但后面的同学可能因为太远看不清老师写的字,或者说老师写错了一个数据要修改的时候,所有学生都要跟着改一遍。连题目都抄错的同学,怎么可能做对题呢?不是同样的标准,怎么评判学生的成绩呢?
但在正式的考试中,老师并不会在黑板上出题学生抄题目答题,而是老师会发给每个同学一份事先出好的试卷,这样在题目上所有同学拿到的都是同一份试卷,学生只负责写上自己的答案,我们也就有了同样的标准来评判每个人的成绩水平。我们将试卷抽象成公共类,每个学生的试卷继承这个试卷公共类,只在自己类里实现“答案”即可。可见其实模板方法模式的类结构很简单。
我们根据上面所举的例子,来具体实现模板方法模式。
首先是抽象公共类:
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 }
在敲完实现模板方法模式代码后,我们给模板方法模式一个定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。——《大话数据结构》