一 定义
在面向对象的程序设计中,我们经常会遇到这种情况,设计一个系统时,知道了算法所需的关键步骤,而且确定了步骤的执行顺序,但某些步骤的具体实现还未知,后者说某些步骤的实现和具体的环境相关。
例如,你去银行办理业务,流程大致为,取号,排队,办理具体业务等,这些步骤的执行顺序已经确定了,可以放在父类中实现,但是办理具体的业务因人而异,有可能是存款,取款,转账等,这个是可以延迟到子类中的。
定义:定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式可以用四个字概括:流程封装
二 模式结构
角色介绍:
- AbsTemplate:抽象类,定义了一套算法框架。
- ConcreteImplA、ConcreteImplB:具体的实现。
三 实例
我们以冲泡咖啡和泡茶为例,冲泡的基本流程是:
1、把水煮沸
2、用煮沸的水冲泡咖啡或者茶叶
3、把冲泡好以后的咖啡或者茶叶倒入杯子
4、加蜂蜜(茶叶)或者加糖和牛奶(咖啡)
算法的框架已经有了,具体的实现可能要延迟到子类中。具体代码实现如下:
- 算法抽象类
该抽象类中已经定义了算法的实现步骤,但是第二步和第四步定义成抽象的,需要在子类中实现。
public abstract class Beverage {
/**
* 煮开水
*/
public void boilWater(){
System.out.println("煮开水");
}
/**
* 冲泡
*/
public abstract void brew();
/**
* 倒进杯子
*/
public void pourInCup(){
System.out.println("倒进杯子");
}
/**
* 加点东西
*/
public abstract void addSomething();
/**
* 冲泡茶叶或者咖啡流程
* 用final修饰,防止算法被改写
*/
public final void create(){
boilWater();
brew();
pourInCup();
addSomething();
}
}
- 具体的实现
实现冲泡咖啡和茶,实现抽象类中定义的抽象方法。
public class Coffee extends Beverage{
@Override
public void brew() {
System.out.println("用水冲咖啡");
}
@Override
public void addSomething() {
System.out.println("往咖啡里加点糖或者牛奶");
}
}
public class Tea extends Beverage{
@Override
public void brew() {
System.out.println("用水冲茶");
}
@Override
public void addSomething() {
System.out.println("加点蜂蜜");
}
}
- 测试代码
// 制作咖啡
System.out.println("------制作coffee----------");
Coffee coffee=new Coffee();
coffee.create();
// 制作茶
System.out.println("------制作tea----------");
Tea tea=new Tea();
tea.create();
-
运行结果
四 优缺点
- 封装不变部分,扩展可变部分
把认为是不变的部分的算法封装到父类中,而可变部分则可以通过继承来继续扩展。 - 提取公共部分代码,便于维护
- 行为由父类控制,子类实现
缺点:模板方法会带来代码阅读的难度,会让用户觉得难以理解。
五 使用场景
- 多个子类有公有的方法,并且逻辑基本相同。
- 重要,复杂的算法,可以把核心算法设计成模板方法,周边的相关细节功能则由各个子类实现。
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
网友评论