模板模式
简介:
设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。
定义:
- 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),
在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法
实现,但调用将以抽象类中定义的方式进行。 - 简单说,模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子
类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定
步骤 - 这种类型的设计模式属于行为型模式。
模式的结构:
模板方法模式包含以下主要角色。
(1) 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。
① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
② 基本方法:是整个算法中的一个步骤,包含以下几种类型。
抽象方法:在抽象类中申明,由具体子类实现。
具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。钩子就是给子类一个授权,让子类来决定模板方法的逻辑执行。就比如在炒西红柿鸡蛋的时候,由子类去决定是否要加调料。我们去实现一下
(2) 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
抽象类:
/**
* @author 孙一鸣 on 2020/2/14
* 抽象模板结构
*/
public abstract class AbstractClass {
//模板方法 用来控制子类的顺序 要想有人生必须按老爸的人生顺序来
//声明final不让子类覆盖这个方法,防止改变人生顺序
public final void 人生() {
学习();
工作();
if (hasLove()) {
爱情();
}
}
//家里穷更得用工学习
public void 学习() {
System.out.println("每天晚上趴在邻居窗上学习");
}
//工作必须稳定
public void 工作() {
System.out.println("从一而终");
}
//恋爱自由 让儿子自由恋去,随意找对象
public abstract void 爱情();
//假如我们想要有一个儿子,不想结婚,但是抽象方法必须要实现
//这个时候我们需要 -- 钩子方法
//提供一个默认或者空的实现
boolean hasLove() {
return true;
}
}
具体子类A:
/**
* 好儿子 按照父亲定义的抽象模板类 走完人生
*
* @author 孙一鸣 on 2020/2/14
*/
public class ConcreteClassA extends AbstractClass{
@Override
public void 学习() {
//儿子不认可父亲的学习方法 考高分影响同学关系
System.out.println("高考状元。。");
}
//父亲给我爱情自由 一定好好谈恋爱
@Override
public void 爱情() {
System.out.println("肤白貌美大长腿...");
}
}
具体子类B:
/**
* 坏儿子 也按照父亲定义的抽象模板类 走完人生
*
* @author 孙一鸣 on 2020/2/14
*/
public class ConcreteClassB extends AbstractClass {
@Override
public void 学习() {
//学习无用
System.out.println("0分万岁...");
}
//随意结合
@Override
public void 爱情() {
System.out.println("矮穷矬...");
}
}
具体子类C:
/**
* 不想结婚的儿子 也按照父亲定义的抽象模板类 走完人生
*
* @author 孙一鸣 on 2020/2/14
*/
public class ConcreteClassC extends AbstractClass {
@Override
public void 学习() {
//学习无用
System.out.println("60分万岁...");
}
//随意结合
@Override
public void 爱情() {
//因为不想要结婚 所以空实现
}
//子类通过覆盖的方式去挂载钩子函数
@Override
boolean hasLove() {
return false;
}
}
模板方法模式的注意事项和细节
- 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算
法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改 - 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接
使用。 - 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
- 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,
使得系统更加庞大 - 一般模板方法都加上final关键字, 防止子类重写模板方法.
- 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一
系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模
式来处理