一、模板方法模式简介
模板方法模式:定义一个操作中的算法的骨架,将一些步骤延迟到子类。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
组成要素去理解,包括抽象类和继承的子类两部分。提取公共的方法,也就是行为,子类继承实现自己的拓展。
Spring框架里有jdbc模板,用的就是这个模式。
二、场景分析
多个考生,拿到相同的试卷,填写不同的答案。
变化的部分是:考生是多个,以及每个考生填写的每道题的答案不同(除非都是学霸和欧皇)
不变的部分是:试卷的题目,考生答试卷的行为。
三、第一次实现
简单来说就大杂烩装所有,代码如下
public class ExampleFirst { public void test1(){ System.out.println("test1是爸爸的爸爸叫什么 A 大人 B 老子 C 夜夜"); System.out.println("张三 选 B"); } public void test2(){ System.out.println("test1是爸爸的儿子叫什么 A 小屁孩 B 名字 C 孙子"); System.out.println("张三 选 B"); } }
来一个张三考生,我建一个类,来个李四,就再建一个类,然后在控制台分别new对象调用
看问题
- 代码重复量太多,需要抽取,解决方法就是创建抽象类。抽取的东西是问题(不变的部分)
- 创建问题类,考生姓名作为问题类的属性。
四、第二次实现
按照上面的总结,代码抽取之后的抽象类如下
public abstract class ExampleFather { public String name; public ExampleFather(String name){ this.name=name; } public void test1(){ System.out.println("test1是爸爸的爸爸叫什么 A 大人 B 老子 C 夜夜"); } public void test2(){ System.out.println("test1是爸爸的儿子叫什么 A 小屁孩 B 名字 C 孙子"); } }
张三来考试,则可以
public class ZsToExample extends ExampleFather { public ZsToExample(String name) { super(name); } public void test1(){ super.test1(); System.out.println(super.name+"的答案是B"); } public void test2(){ super.test2(); System.out.println(super.name+"的答案是B"); } }
李四也一样,控制程序和调用结果
public static void main(String[] args) { ExampleFather zhangsan=new ZsToExample("张三"); zhangsan.test1(); zhangsan.test2(); }
第一次抽取后,少了问题的代码重复性减少,创建子类的数量就是一个,这个不太正确,正确的应该是每个子类一个,恋爱里不分对错,喜欢就好
不变的部分里还有一个就是考生回答问题的行为。答案有两个属性,一是问题号,二是答案选项。
这里抽取有两个思路,一是考生回答问题的行为当做是另一个行为,即书里的方式,每个问题都有一个答案的方法,二是把答案当做问题的属性,也就是变量传参,(选这个)
五、第三次抽取
答案是问题内部人员,只给属性变量即可,抽取的代码如下:
public abstract class ExampleFather { public String name; public ExampleFather(String name){ this.name=name; } public void test1(String answer){ System.out.println("test1是爸爸的爸爸叫什么 A 大人 B 老子 C 夜夜"); System.out.println(this.name+"的答案是"+answer); } public void test2(String answer){ System.out.println("test2是爸爸的儿子叫什么 A 小屁孩 B 名字 C 孙子"); System.out.println(this.name+"test2的答案是"+answer); } }
或者也可以当成另一种行为,则回答答案就需要知道题号,则抽取完之后代码如下:
public abstract class ExampleFather { public String name; public ExampleFather(String name){ this.name=name; } public void test1(String answer){ System.out.println("test1是爸爸的爸爸叫什么 A 大人 B 老子 C 夜夜"); answer("test1",answer); } public void test2(String answer){ System.out.println("test2是爸爸的儿子叫什么 A 小屁孩 B 名字 C 孙子"); answer("test2",answer); } public void answer(String count,String answer){ System.out.println(this.name+count+"的答案是"+answer); } }
六、总结
书里的目的是,以模板模式实现对考卷类的最大的复用,主体是试卷,所以需要n个考生子类,当主体是考生是,就只需要一个子类。
来看一下逻辑衍生的行为:
- 将不变的东西抽取到父类,所以有了试卷试题抽象类。
- 将变化封装,每个考生考题的答案放到子类来实现
模板方法模式的特点是
把不变的行为搬到超类,去除子类中重复的代码,它提供了很好的代码复用的平台(为毛感觉就是继承的作用,调用那有一点点多态)
使用场景:当一个问题需要一系列步骤构成的程序去执行,而这个过程从更高的层次上是相同的,只是每个步骤的细节上有所不同,这时候可以考虑使用模板模式。将这些单一的行为搬到父类。
自由在高处,变化是不变的,去抽象变化本身。