这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战
什么是模板方法模式(Template Method)
概念
模板方法模式(Template Method)属于行为型模式,这个模式的名称听着有点让人摸不着头脑。模板方法模式是指在抽象类中定义一个非抽象方法,在这个非抽象方法中定义好如何调用抽象方法,而这些抽象方法实现交给子类去完成,相当于父类定好了框架,子类负责实现这个框架的内容。
在面向对象语言中,我们如何使用抽象类,并在其中定义非抽象方法和抽象方法,模板方法模式给出了一个可以提供我们模仿的规范。
现实生活中也有非常多这样的例子,像一台电脑,电脑主板已经固定好要什么东西了,CPU、硬盘、内存条,这些我们都可以自己去组装;还有画画,一般都是先画一个基本的框架,剩下的细节和上色,不同人来画都有可能不同。
优点
- 符合开放封闭原则。想要实现不同的功能,只需要实现不同的子类即可,提高了系统的扩展性。
- 父类提取了复用的代码,提高了代码的复用性和可维护性。
缺点
- 提高了类间的耦合度。因为是使用继承的方式来实现的,当抽象类新增了一个抽象方法,所有子类也得新增。
- 提高了代码的阅读难度。这是一种反向的控制结构,一般情况下是子类调用父类中的方法,而这里是父类调用子类的方法,这也让我们的设计更加的抽象,也更难的读懂。
所有设计模式都是在合适的场景使用才会有奇效,强行使用只会适得其反。
原则
“+”代表遵守,“-”代表不遵守或者不相关
| 原则 | 开放封闭 | 单一职责 | 迪米特 | 里氏替换 | 依赖倒置 | 接口隔离 | 合成复用 |
|---|---|---|---|---|---|---|---|
| + | + | - | + | + | - | - | |
适用场景
- 多个子类中有相同的方法,逻辑基本相同。
- 一个方法的基本逻辑/主体架构是确定的,但有些地方会进场变动。
如何实现
想要实现模板方法模式,需要以下两样东西:
- 模板方法:抽象类中的非抽象方法,定义基本的逻辑骨架,调用基本方法的顺序以及处理操作。
- 基本方法: 抽象方法:在抽象类中声明,由子类实现。 非抽象方法:在抽象类中已经实现,子类继承。 钩子方法:在抽象类中空实现的方法,子类可以不实现。
类图
这里贴个模板方法模式的类图
在TemplateMethod中就定义了其他方法的调用顺序。
例子
我们都经常去喝奶茶,那么热的天没有什么比喝一杯冰冰凉凉的奶茶舒服了,如果有,那一定是冰可乐。
做奶茶一般都是有一个固定的步骤的,加奶茶粉、加水、加糖&调料、摇、加冰、打包,这就是一个模板,这里的步骤有些是不变的,有些是根据客人的要求来定的,我们去买奶茶可以定几分糖、少冰多冰。
类图
代码
奶茶抽象类:定义模板方法、抽象方法和非抽象方法
/**
* 奶茶抽象类
*
* @author xuxiaobai
*/
abstract class MilkyTea{
/**
* 做奶茶
* 模板方法最好加个final
*/
final void process(){
addTeaPowderWithMilk();
addSugarAndCondiment();
addWrite();
shake();
addIce();
pack();
}
/**
* 加奶茶粉
*/
abstract void addTeaPowderWithMilk();
/**
* 加糖浆和调料
*/
abstract void addSugarAndCondiment();
/**
* 加水
*/
void addWrite(){
System.out.println("加水");
}
void shake(){
System.out.println("使劲摇");
}
abstract void addIce();
void pack(){
System.out.println("封口");
System.out.println("装袋");
System.out.println("完成");
}
}
无糖多冰绿奶茶:实现抽象方法
/**
* 无糖多冰绿奶茶
*
* @author xuxiaobai
*/
public class NoSugarManyIceGreetMilkyTea extends MilkyTea {
@Override
void addTeaPowderWithMilk() {
System.out.println("加绿茶粉&奶");
}
@Override
void addSugarAndCondiment() {
System.out.println("不加糖");
}
@Override
void addIce() {
System.out.println("加半杯冰");
}
}
测试类:
/**
*
* @author xuxiaobai
*/
public class TemplateMethodTest {
public static void main(String[] args) {
//现想要一个无糖多冰绿奶茶
MilkyTea milkyTea=new NoSugarManyIceGreetMilkyTea();
//开始制作
System.out.println("---无糖多冰绿奶茶制作过程---");
milkyTea.process();
/**
* 结果:
* ---无糖多冰绿奶茶制作过程---
* 加绿茶粉&奶
* 不加糖
* 加水
* 使劲摇
* 加半杯冰
* 封口
* 装袋
* 完成
*/
}
}
这里简单地写了一个无糖多冰绿奶茶类,这里的很多方法都是在抽象类中直接使用,然后实现类去实现,你大概体会一下模板方法的使用即可。
总结
模板方法模式提供了反向控制结构的指导,定义了抽象类中的方法怎么和实现类的方法去交互。其实也不需要特别地去记这个设计模式,只要知道在抽象类中,非抽象方法可以使用抽象方法,抽象方法呢又需要子类去实现,就可以了,到了特定的情况,在做代码优化的时候自然而然地就会使用模板方法模式了。
\