生活中有很多按步骤才能完成的事,比如我们想进房间,需要先将门打来,然后才能进去,进去之后再把门关上。开门和关门是固定的步骤,而进入房间的步骤则不是固定的,它可以有多种方式,走着进去、跑着进去、跳着进去等都可以。类似这种多个步骤才能完成的事,在软件世界称之为模板方法模式
模板方法模式(Template Method Pattern):定义了一个操作中的算法框架,并将一些步骤延迟到子类中。使得子类在不改变算法结构的情况下,重新定义算法的某些步骤。模板方法是一种类行为型模式
完成模板方法模式需要2个角色
抽象类(AbstractClass):定义了一系列基本操作,这些操作可以是具体的,也可以是抽象的。在抽象类中实现一个模板方法,用于定义一个算法框架
具体子类(ConcreteClass):抽象类的子类,实现父类中声明的抽象方法
下面代码演示模板方法模式
定义抽象类
相关说明在代码中
package com.design.behavioral.templatemethod;
/**
* 抽象类
*/
public abstract class AbstractClass {
private boolean isEffective = false;
/**
* 通过构造设置钩子方法返回值
* @param isEffective
*/
public AbstractClass(boolean isEffective) {
this.isEffective = isEffective;
}
/**
* 固定方法,设置成 final
*/
public final void primitiveOPeration1(){
System.out.println("开始执行");
}
/**
*有默认实现,可以被子类重写的方法
*/
public void primitiveOPeration2(){
System.out.println("默认执行,可被重写");
}
/**
* 钩子方法
* @return
*/
public boolean isEffective(){
return isEffective;
}
/**
* 被钩子方法控制的方法
*/
public void effectiveOPeration(){
System.out.println("是否有效操作");
}
/**
* 抽象方法,有子类实现
*/
public abstract void primitiveOPeration3();
/**
* 固定方法,设置成 final
*/
public final void primitiveOPeration4(){
System.out.println("结束执行");
}
/**
* 模板方法,定义算法骨架,内部流程固定不变
*/
public final void templateMethod(){
this.primitiveOPeration1();
this.primitiveOPeration2();
if (this.isEffective()){
this.effectiveOPeration();
}
this.primitiveOPeration3();
this.primitiveOPeration4();
}
}
具体子类.
package com.design.behavioral.templatemethod;
/**
* 具体子类
*/
public class ConcreteClass extends AbstractClass{
public ConcreteClass(boolean isEffective) {
super(isEffective);
}
@Override
public void primitiveOPeration3() {
System.out.println("子类实现操作");
}
}
类图如下
测试调用
package com.design.behavioral.templatemethod;
/**
* 模板方法模式
*/
public class TestMain {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClass(true);
abstractClass.templateMethod();
}
}
调用结果
模板方法模式总结
优点:父类定义算法,子类实现细节处理,保证了步骤的执行次序;提高代码复用性;通过钩子方法,实现子类对父类的反向控制;符合开闭原则
缺点:每一个基本方法的不同实现都需要一个子类,因此将导致类的数目增加;增加系统实现的复杂度;如果父类中增加新方法,则所有的子类都需要修改
适用场景:对复杂的算法进行分割,一次性实现算法不变的部分,将可变的行为留给子类实现;将各个子类中的公共行为提取出来并集中到一个公共父类,避免代码重复;需要通过子类决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制