定义一个模板结构,将具体内容延迟到子类去实现。
作用: 在不改变模板结构的前提下在子类中重新定义模板中的内容,模板方法模式是基于”继承“的。
解决的问题:
- 提高代码复用性 将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中
- 实现了反向控制 通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制,符合“开闭原则”
1、模式原理
1.1 UML类图
1.2 实例讲解
通过一个例子来进一步了解模板方法模式:
- 背景:现在有一套试卷给学生做,题目是一样的
- 冲突:题目一样,但是每个学生的答案不一样
- 解决方式:父类定义题目和答案,子类继承实现答案相关的属性
使用步骤
- 步骤1:创建抽象模板结构(Abstract Class): 试卷的结构
public abstract class TestPaper {
//答题的情况
final void process(){
this.question1();
this.answer1();
this.question2();
this.answer2();
this.question3();
this.answer3();
}
void question1(){
System.out.println("题目1");
}
void question2(){
System.out.println("题目2");
}
void question3(){
System.out.println("题目3");
}
abstract void answer1();
abstract void answer2();
abstract void answer3();
}
- 步骤2:创建具体模板(Concrete Class),即不同学生的答卷
public class StudentA extends TestPaper {
@Override
void answer1() {
System.out.println("答案:a");
}
@Override
void answer2() {
System.out.println("答案:c");
}
@Override
void answer3() {
System.out.println("答案:d");
}
}
public class StudentB extends TestPaper {
@Override
void answer1() {
System.out.println("答案:c");
}
@Override
void answer2() {
System.out.println("答案:a");
}
@Override
void answer3() {
System.out.println("答案:d");
}
}
- 步骤3:(客户端)老师收卷,查看答题情况
public class Teacher {
public static void main(String[] args) {
System.out.println("考试A的答卷");
StudentA studentA = new StudentA();
studentA.process();
System.out.println("考试B的答卷");
StudentB studentB = new StudentB();
studentB.process();
}
}
- 结果输出:
考试A的答卷 题目1 答案:a 题目2 答案:c 题目3 答案:d 考试B的答卷 题目1 答案:c 题目2 答案:a 题目3 答案:d
2、优缺点
2.1 优点
- 提高代码复用性 将相同部分的代码放在抽象的父类中。
- 提高了拓展性 将不同的代码放入不同的子类中,通过对子类的扩展增加新的行为,实现了反向控制。
- 通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,实现了反向控制,而且符合“开闭原则”。
2.2 缺点
引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂度。
3、应用场景
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现;
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;
- 控制子类的扩展。