模版方法模式
定义
模版方法模式基于Java继承机制,在抽象模版类定义一个算法的骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下即可重定义该算法的某些特定步骤。
结构
- 抽象模版类:负责给出一个算法的轮廓和骨架。有一个模版方法和若干基本方法构成。
模版方法:定义一套算法骨架,按某种顺序调用其包含的基本方法。
基本方法:算法骨架的某些步骤进行具体实现,包含以下几种类型
- 抽象方法:在抽象类中声明,由子类实现。
- 具体方法:在抽象类中已经实现,子类可继承或重写。
- 钩子方法:抽象类中已经实现,包括用于判断的逻辑方法和子类重写的空方法两种。
- 子类实现类:实现抽象类中所定义的抽象方法和钩子方法,
优缺点
优点:把公共通用的逻辑封装在父类中实现,提高代码复用性。而把可变部分由子类继承实现,便于子类继续扩展,符合开闭原则。
缺点:对每个不同的实现都需要定义一个子类,会导致类个数增加,增加了系统实现复杂度。若父类添加新的抽象方法,则所有子类都要改一遍。
使用场景
算法整体步骤很固定,但其中个别部分易变时,可以使用模版方法模式。
当多个子类存在公共的行为时,可将其提取出来并集中到一个公共父类,提高代码复用性。
注意:一般模版方法都加final关键字修饰,避免子类对其覆写,防止恶意操作。
代码实践
eg:一个做饭的例子。简单定义一下步骤(模版方法):
- 点火
- 固定食材和口味烹饪
- 关火
抽象模版类
package com.flz.demo.design.templateMethod;
/**
* 模版方法模式基于Java继承实现
* 模版抽象类
*/
public abstract class AbstractCook {
/**
* 模版方法
* 使用final修饰,避免子类对该算法流程篡改
*/
public final void doCook() {
openFire();
cooking();
if (isTasteHookMethod()) {
taste();
}
closeFire();
}
/**
* 抽象方法
*/
protected abstract void cooking();
/**
* 具体方法
*/
protected void openFire() {
System.out.println("点火,准备做饭!");
}
/**
* 具体方法
*/
protected void closeFire() {
System.out.println("关火,做完饭了!");
}
/**
* 钩子方法之判断方法
* 子类可继承或实现自己的味觉要求。
*
* @return
*/
protected boolean isTasteHookMethod() {
return false;
}
/**
* 钩子方法之空方法
*/
protected void taste() {
}
}
具体子类
public class Crayfish extends AbstractCook {
@Override
protected void cooking() {
System.out.println("一份小龙虾");
}
@Override
protected boolean isTasteHookMethod() {
return true;
}
@Override
protected void taste() {
System.out.println("加麻加辣!");
}
}
public class FryRice extends AbstractCook {
@Override
protected void cooking() {
System.out.println("一份蛋炒饭");
}
public static void main(String[] args) {
AbstractCook crayfish = new Crayfish();
crayfish.doCook();
System.out.println("===========");
FryRice fryRice = new FryRice();
fryRice.doCook();
}
}