模板方法模式——《设计模式之禅》
例子
悍马模型抽象接口
// 抽象是所有子类的共性封装
public abstract class HummerModel{
/**
* run();
* 这是一个汇总的方法
*/
final abstract void run(){
this.start();
this.engineBoom();
if(this.isAlarm()){
this.alarm();
}
this.stop();
}
//车辆发动
protected abstract void start();
//车辆停止
protected abstract void stop();
//车辆鸣叫
protected abstract void alarm();
//车辆加速
protected abstract void engineBoom();
//hook函数,约束是否鸣笛
protected boolean isAlarm(){
return true;
}
}
public class HummerH1Model extends HummerModel {
private boolean alarmFlag = true;
protected void alarm(){
System.out.println("悍马H1鸣笛");
}
protected void start(){
System.out.println("悍马H1发动");
}
protected void stop(){
System.out.println("悍马H1停止");
}
protected void engineBoom(){
System.out.println("引擎声音");
}
//hook函数,重新实现可以实现自定义是否鸣笛
protected boolean isAlarm(){
return this.alarmFlag;
}
// 由客户实现是否鸣笛
public void setAlarm(boolean isAlarm){
this.alarmFlag = isAlarm;
}
}
public class HummerH2Model extends HummerModel {
protected void alarm(){
System.out.println("悍马H2鸣笛");
}
protected void start(){
System.out.println("悍马H2发动");
}
protected void stop(){
System.out.println("悍马H2停止");
}
protected void engineBoom(){
System.out.println("引擎声音");
}
//hook函数,重新实现可以实现自定义是否鸣笛
protected boolean isAlarm(){
return false;
}
}
public class Client{
public static void main(String[] args) throws IOException {
HummerModel h1 = new HummerH1Model();
h1.run();
HummerModel h2 = new HummerH2Model();
h2.run();
}
}
模板方法模式的定义
模板方法模式Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm' s structure.
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某特定步骤
模板方法模式的特点
- 模板方法模式确实非常简单,仅仅使用了java的继承机制,其中,AbstractClass叫做抽象模板
- 基本方法:基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法中被调用
- 模板方法:可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑
- 为了安全起见,模板方法一般加修饰符:final防止被恶意修改
- 在类图中有一个角色:具体模板。ConcreteClass1和ConcreteClass2属于具体模板,实现父类所定义的一个或多个抽象方法。也就是父类定义的基本方法在子类中得以实现
抽象模板类
public abstract class AbstractClass{
// 基本方法
protected abstract void doSomething();
// 基本方法
protected abstract void doAnything();
// 模板方法
public void templateMethod(){
/**
* 调用基本方法,完成相关的逻辑
*/
}
}
具体模板类
public class ConcreteClass1 extends AbstractClass{
// 实现基本方法
protected void doAnything(){
// code to do something
}
protected void doSomething(){
// code to do something()
}
}
public class ConcreteClass2 extends AbstractClass{
// 实现基本方法
protected void doAnything(){
// code to do something
}
protected void doSomething(){
// code to do something()
}
}
场景类
public class Client{
public static void main(String[] args) {
AbstractClass class1 = new ConcreteClass1();
AbstractClass class2 = new ConcreteClass2();
// 调用模板方法
class1.templateMethod();
class2.templateMethod();
}
}
注意事项
- 抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则。不需要暴露的属性或方法尽量不要设置为protected属性
- 实现类若非必要,尽量不要扩大父类的访问权限
模板方法模式的优缺点
模板方法模式的优点
-
封装不变部分,扩展可变部分
-
提取公共部分代码,便于维护
-
行为由父类控制,子类实现。
基本方法是由子类实现的,因此子类可以通过扩展的方法增加相应的功能,符合开闭原则
模板方法模式的缺点
- 模板方法模式抽象类定义了部分抽象方法,由子类实现,子类执行的结果对父类产生了影响,会带来代码阅读的难度
模板方法模式的适用场景
- 多个子类有公有的方法,并且逻辑基本相同时
- 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
- 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过hook函数约束行为
扩展:父类调用子类的方法
- 把父类传递到子类的有参构造中,然后调用
- 使用反射的方式调用
- 父类调用子类的静态方法
- 模板方法模式:修改子类的方法,影响父类的行为
网友评论