一、模板模式式定义
- ①:模板模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板模式使得子类可以不改变一个算法的结构,即可重定义该算法的某些特定步骤。
- ②;这种类型的设计模式属于行为型模式。
- ③:为防止恶意操作,一般模板方法都加上
final关键词。
二、模板方法模式的基本结构

AbstractClass是一个抽象类,其实就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体的实现,他给出了一些逻辑的骨架,而逻辑的组成在相应的抽象类中,推迟到了子类实现:
public abstract class AbstractClass {//一些抽象行为,可以理解为重复不变的方法,提取到抽象类public abstract void primitiveOperation1();public abstract void primitiveOperation2();//模板方法,给出了具体逻辑的骨架,而逻辑的组成是一些相应的抽象操作,他们都推迟到子类实现public final void templateMothed() {primitiveOperation1();primitiveOperation2();}}
ConcreteClass实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有一个或者多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是骨架的组成步骤)的不同实现,从而得到的实现都不同:
具体实现ConcreteClassA:
public class ConcreteClassA extends AbstractClass {@Overridepublic void primitiveOperation1() {System.out.println("子类A的操作1");}@Overridepublic void primitiveOperation2() {System.out.println("子类A的操作2");}}
具体实现ConcreteClassB:
public class ConcreteClassB extends AbstractClass {@Overridepublic void primitiveOperation1() {System.out.println("子类B的操作1");}@Overridepublic void primitiveOperation2() {System.out.println("子类B的操作2");}}
上面定义了两个具体的实现,更多的实现其实都是一致的,这里就不多多说了。下面看下客户端代码:
public class Client {public static void main(String[] args) {AbstractClass obj_1 = new ConcreteClassA();obj_1.templateMothed();AbstractClass obj_2 = new ConcreteClassB();obj_2.templateMothed();}}
输出内容如下:
子类A的操作1子类A的操作2子类B的操作1子类B的操作2
三、没有使用设计模式
笔者就以抄试卷模式为名来阐述重复不变带来的不便,下面会对该模式进行改进:
学生甲抄的试卷:
public class TestPaperA {//试卷第一题public void testQuestion1() {System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈");System.out.println("答案:C");}//试卷第二题public void testQuestion2() {System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");System.out.println("答案:C");}//试卷第三题public void testQuestion3() {System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");System.out.println("答案:B");}}
学生乙抄的试卷:
public class TestPaperB {//试卷第一题public void testQuestion1() {System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈");System.out.println("答案:A");}//试卷第二题public void testQuestion2() {System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");System.out.println("答案:C");}//试卷第三题public void testQuestion3() {System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");System.out.println("答案:D");}}
客户端代码:
public class Client {public static void main(String[] args) {System.out.println("========== 学生甲的试卷 ==========");TestPaperA stuA = new TestPaperA();stuA.testQuestion1();stuA.testQuestion2();stuA.testQuestion3();System.out.println("========== 学生乙的试卷 ========== ");TestPaperB stuB = new TestPaperB();stuB.testQuestion1();stuB.testQuestion2();stuB.testQuestion3();}}
输出内容如下:
========== 学生甲的试卷 ==========小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈答案:C全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛答案:C《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴答案:B========== 学生乙的试卷 ==========小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈答案:A全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛答案:C《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴答案:D
很容易发现上面两个学生抄的试卷有很多重复的地方,比如试卷的题目,输出答案的方法。这些都在每个学生试卷类中混合在一起了,既不利于维护,也不利于浏览,下面看一下模板方法模式是怎么改进的。
四、使用模板模式进行改造
将每个学生试卷的重复部分提取出来,题目、作答等等。首先改造试卷类,将该类改为抽象类。在该类中我添加了三个抽象的方法用于子类实现。
学生都是要作答的,但是答案不一样,所以可以将作答的过程作为重复不变的方法提取出来。
创建TestPaper试卷模板抽象类:
为防止恶意操作,一般模板方法都加上
final关键词
public abstract class TestPaper {//试卷第一题public void testQuestion1() {System.out.println("小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈");System.out.println("答案:" + answer1());}//试卷第二题public void testQuestion2() {System.out.println("全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛");System.out.println("答案:" + answer2());}//试卷第三题public void testQuestion3() {System.out.println("《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴");System.out.println("答案:" + answer3());}//这三个钩子方法是给每个子类去实现,并返回答案的public abstract String answer1();public abstract String answer2();public abstract String answer3();//模板方法,考试的过程,定义基本的考试过程,子类回调public final void exam() {testQuestion1();testQuestion2();testQuestion3();}}
创建TestPaper抽象类的TestPaperA具体实现类:
public class TestPaperA extends TestPaper {@Overridepublic String answer1() {return "A";}@Overridepublic String answer2() {return "B";}@Overridepublic String answer3() {return "D";}}
创建TestPaper抽象类的TestPaperB具体实现类:
public class TestPaperB extends TestPaper {@Overridepublic String answer1() {return "C";}@Overridepublic String answer2() {return "A";}@Overridepublic String answer3() {return "A";}}
客户端代码:
public class Client {public static void main(String[] args) {TestPaper testPaper = new TestPaperA();testPaper.exam();}}
输出内容如下:
小龙女是杨过的什么亲戚?() A.小姨妈 B.大姨妈 C.姑妈 D.舅妈答案:A全真教的首任掌门是谁?A.周伯通 B.欧阳锋 C.王重阳 D.西门吹牛答案:B《天龙八部》中被封为南院大王的大侠是谁?A.段誉 B.乔峰 C.慕容复 D.段智兴答案:D
五、总结
模板方法模式就是为了将重复不变的代码提取到一个抽象类中。当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。
