概述
在面向对象程序设计中,程序员往往会遇到这种情况:设计一个系统时知道算法所需的关键步骤,而且确定这些步骤的执行顺序,但某些步骤的具体实现还不知道,或者说某些步骤的实现与具体的环境相关
例如:我们在玩王者荣耀的时候,我们都需要先匹配游戏,然后挑选英雄,然后再进入王者峡谷。但是选的英雄却可以是不一样的,一样的步骤就可以在父类实现,然后子类继承就好,挑选英雄可以在子类进行实现所挑选的英雄(兰陵王、鲁班...)
模板方法模式定义:
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以在不改变该算法结构的情况下重定义该算法的某些特定步骤。
结构
模板方法 (template method) 模式中包含以下主要角色:
- 抽象类 (Abstract Class):负责给出一个算法的轮廓和骨架,由一个模板方法和若干个基本方法组成
- 模板方法:定义算法的骨架,按照某种顺序调用其包含的基本方法
- 基本方法:实现算法各个步骤的方法,是模板方法的组成部分,可以分为一下三种
- 抽象方法:方法的实现与具体环境有关,需要具体子类去实现
- 具体方法:通用的方法,声明和实现都在抽象类中完成
- 钩子方法:抽象类中实现,包含用于判断的逻辑方法( isXXX():boolean)和需要子类重写的空方法
- 具体子类 (Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,他们是一个顶级逻辑的组成步骤
实例:
玩王者荣耀一般都要经过这几个步骤:匹配队友、挑选英雄、进入王者峡谷。现在以模板方法来模拟:
代码实现:
package com.ag.action;
public class TemplateMethodMode {
public static void main(String[] args) {
AbstractClass abstractClass = new LuBan();
abstractClass.proccess();
}
}
abstract class AbstractClass{
public void pipei(){
System.out.println("匹配队友...");
}
public abstract void choiceMan();
public void joinXiaGu(){
System.out.println("欢迎来到不是人的荣耀");
}
public void proccess(){
pipei();
choiceMan();
joinXiaGu();
}
}
class LuBan extends AbstractClass{
public void choiceMan() {
System.out.println("选择鲁班");
}
}
class LanLingWang extends AbstractClass{
public void choiceMan() {
System.out.println("选择兰陵王");
}
}
优点:
- 提高代码的复用性:将相同部分的代码放在抽象的父类中,将不同的代码放在不同的子类中
- 实现反向控制:通过一个父类调用其子类的操作,通过对子类的具体实现扩展不用的行为,实现反向控制,符合 “开闭原则”
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计更加抽象
- 父类中的抽象方法有子类实现,子类执行的结构会影响父类的结果,导致一种反向的控制结构,提高代码阅读的困难
适用场景
算法的整体步骤很固定,但其中个别部分易变时,可以使用模板方法,将容易变的部分抽象出来,供子类实现
需要通过子类类决定父类算法中某个步骤是否执行,实现子类对父类的反向控制