文章目录
模板方法模式
定义:指在父类中定义了一个主要算法的骨架流程,并且允许子类可以不改变算法的结构为一个或者多个个性化步骤提供实现,算法的流程执行顺序是由父类掌控的,子类只能配合。实际上是封装了一个固定流程,该流程由几个步骤组成,具体步骤可以由子类进行不同实现,从而让固定的流程产生不同的结果。
优点:
- 封装不变,扩展可变:父类封装了具体流程以及实现部分不变行为,其它可变行为交由子类进行具体实现;
- 流程由父类控制,子类进行实现:框架流程由父类限定,子类无法更改;子类可以针对流程某些步骤进行具体实现,实现不会改变流程结构。
- 代码复用:去除子类中的重复代码,很好的代码复用。
- 符合开闭原则:通过父类调用子类的操作,通过对子类的扩展增加新的行为。
缺点:
抽象父类需要子类实现,导致了类的数量增加,整个体系复杂。
适用场景:
- 一次性实现一个算法的不变部分,并将可变的行为留给子类去实现
- 各子类的公共行为被提取出并集中在公共的父类中,从而避免代码重复
模式分析:
模板方法模式包含如下角色:
- 抽象类
- 具体子类
方法分析:
模板方法封装了基本方法,每个子类根据自身需求对基本方法进行不同的实现,之后子类对象调用模板方法时,会得到不同的结果。
-
模板方法:是抽象类【而非接口】中的、把基本操作方法组合在一起形成的一个总算法或一个总行为的方法。在抽象类中直接定义,子类不加修改直接继承。是一个具体方法,其内部封装了一个流程框架。内部的方法流程,可以是具体方法,也可以是抽象方法。
-
基本方法:是模板方法中封装的内部方法。
a.抽象方法:声明在抽象父类中,有abstract修饰,实现在子类中。
b.具体方法:声明或实现在抽象父类中,子类可以对其继承使用或者覆盖,无abstract修饰。
c.钩子方法:声明或实现在抽象父类中,子类可以对其继承使用或者覆盖。通常父类给出的实现是非空默认实现或者空实现。
钩子方法有两类:
(1)与具体步骤挂钩,以确定在不同条件下执行模板方法中的不同步骤,返回值通常为boolean,用于条件判断。
(2)实现体为空的方法,子类根据需要实现或继承该方法。模板如下:
//模板方法,其内部均为基本方法。
public void template()
{
open();
display();
ok();
if(isPrint())
{
print();
}
}
//基本方法——钩子方法,根据钩子方法来判断print()是否执行。
private boolean isPrint() {
return true;
}
//基本方法——钩子方法
private void ok() {
}
//基本方法——具体方法
public void print(){
//实现代码 一般是所有子类共有部分
}
//基本方法——具体方法
public void open(){
//实现代码 一般是所有子类共有部分
}
//基本方法——抽象方法
public abstract void display(){}
实例说明:
场景:银行业务模板,流程为 取号——办理业务——填写单子——反馈评分 ,不同的业务子类根据自身实际业务来决定办理什么业务以及是否填写单子。
代码如下:
AbstractTemplateClass
/**
* 抽象模板类
*/
public abstract class AbstractTemplateClass {
/**
* 取号
* 基本方法—具体方法
*/
private void takeNumber(){
System.out.println("取号");
}
/**
* 反馈评分
* 基本方法—具体方法
*/
private void evaluate(){
System.out.println("反馈评分");
}
/**
* 具体操作 子类必须继承实现
* 基本方法—抽象方法
*/
public abstract void transact();
/**
* 基本方法—钩子方法
* 子类根据自身情况决定是否调用
*/
public boolean isWirte()
{
return false;
}
/**
* 根据钩子方法,决定是否调用
* 基本方法—具体方法
*/
private void write()
{
System.out.println("写单子");
}
/**
* 模板方法
*/
public void template()
{
this.takeNumber();
this.transact();
if(isWirte())
{
this.write();
}
this.evaluate();
}
}
Deposit
/**
* 存款类—需要填写单子
*/
public class Deposit extends AbstractTemplateClass{
public boolean flag;
public Deposit(boolean flag)
{
this.flag=flag;
}
@Override
public boolean isWirte() {
return flag;
}
@Override
public void transact() {
System.out.println("我要存款");
}
}
Transfer
/**
* 转账类—不写单子
*/
public class Transfer extends AbstractTemplateClass{
@Override
public void transact() {
System.out.println("我要转账");
}
}
Withdraw
/**
* 取款类—不写单子
*/
public class Withdraw extends AbstractTemplateClass{
@Override
public void transact() {
System.out.println("我要取款");
}
}
BankTest
/**
* 测试类
*/
public class BankTest {
public static void main(String[] args) {
//需要填写表单 true
Deposit deposit=new Deposit(true);
deposit.template();
System.out.println();
Transfer transfer=new Transfer();
transfer.template();
System.out.println();
Withdraw withdraw=new Withdraw();
withdraw.template();
System.out.println();
}
}
运行结果如下:
取号
我要存款
写单子
反馈评分
取号
我要转账
反馈评分
取号
我要取款
反馈评分
参考书籍:
设计模式.刘伟.胡志刚.郭克华.清华大学出版社