思考:
设计一个系统,知道了算法所需的关键步骤,而且明确这些步骤的执行顺序,但某些步骤的具体实现未知,或者说某些步骤的实现与具体的环境有关,系统该如何设计?
例如:
1、去银行办理业务,一般有四个流程:取号、排队、办理具体业务、对工作人员进行评价。其中取号、排队和对工作人员的评价是对每个客户都是一样的,办理具体的业务不同(可能存款、取款、理财等)
2、生活中的规律:起床、吃饭、做事、睡觉。其中起床、吃饭、睡觉对每个人来说动作都是一致的,做事是不同的(可能上学、上班、运动等)
实现:
普通实现:可能在一个类定义一个方法,固定的流程直接操作,未知的用if语句去判断,如下代码,如果这么操作,当添加新的操作,就要修改原来的代码,不易操作和扩展(违法代码开闭原则)
package com.project.templeteMethod;
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.method("上学");
}
public void method(String type) {
System.out.println("起床");
System.out.println("吃饭");
if("上学".equals(type)) {
System.out.println("去上学");
}else if("上班".equals(type)) {
System.out.println("去上班");
}//……
System.out.println("睡觉");
}
}
使用模板方法模式实现:
1、定义抽象类/抽象模板(算法的轮廓与骨架,一个模板方法和若干个基本方法构成)
模板方法:按某种顺序调用其包含的基本方法
基本方法:抽象方法(抽象类中声明,由子类实现);具体方法(抽象类中已实现的方法);钩子方法(抽象类中已实现的方法,包括用于判断的逻辑方法和需要子类重写的空方法)
package com.project.templeteMethod;
public class TestTemplateMethod {
public static void main(String[] args) {
AbstractTemplateMethod atm = new ConcreteClass();
atm.templateMethod();
}
}
//抽象模板方法
abstract class AbstractTemplateMethod {
//模板方法
public void templateMethod() {
templateExecute1();
realExecute1();
if(hookMethod()) {
realExecute2();
}
templateExecute2();
}
//具体模板方法
private void templateExecute1() {
System.out.println("执行模板方法1");
}
//具体模板方法
private void templateExecute2() {
System.out.println("执行模板方法2");
}
//钩子方法
protected boolean hookMethod() {
return false;
}
//抽象方法,子类去实现
abstract void realExecute1() ;
abstract void realExecute2() ;
}
//具体实现
class ConcreteClass extends AbstractTemplateMethod{
@Override
void realExecute1() {
System.out.println("扩展执行1");
}
@Override
void realExecute2() {
System.out.println("扩展执行2");
}
//覆盖钩子
@Override
protected boolean hookMethod() {
return true;
}
}
模式的结构与实现
模板方法模式需要注意抽象类与具体子类之间的协作。它用到了虚函数的多态性技术以及“不用调用我,让我来调用你”的反向控制技术
模式的应用场景
1、算法整体步骤固定,个别步骤具体实现易变,这时候实现模板方法,将易变的部分抽象出来,由子类实现
2、当多个子类有公共的行为时,可以将重复的行为提取到父类中,以避免代码重复;识别代码中的不同之处,并将不同之处分离成新的操作。新的模板方法替换这些不同的操作
3、当需要控制子类的扩展时,模板方法使用钩子操作,定义子类是否执行该操作
模式的特点:
一个操作中的算法骨架,将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式
优点:
- 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
- 它在父类中提取了公共的部分代码,便于代码复用。
- 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
- 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。