模板方法模式
定义:
模板方法模式是在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
类图:
这里涉及到两种角色:
1. 抽象模板:
定义了一个或多个抽象操作,以便让子类实现。
定义了一个模板方法,给出了一个顶级逻辑骨架,组装了操作的逻辑步骤,子类不可改变。
2. 具体模板
一般有多个具体模板角色,每个模板处理不同的业务
每个具体模板都要继承抽象模板类,实现抽象方法。
核心:子类可以替换父类的可变部分,但是不可以修改模板方法的顶级逻辑。
模式中的方法:
1. 模板方法
定义在抽象类中,把基本方法和钩子方法组合起来的final方法,封装了不可变的逻辑行为。
一个抽象类可以有多个模板方法,而不限于1个。每个模板方法都可以调用任意多个具体方法。
2. 基本方法
基本方法分三种:
i 抽象方法:定义在父类中的方法,由子类实现
ii 具体方法:由父类声明并实现,一般是父类私有方法。不需要子类重写。
iii 钩子方法:由父类定义的普通方法,子类可以重写,也可以不重写。通常父类会给出一个空实现,作为方法的默认实现。
实例:
AbstractFridge:抽象类,定义模板方法
package com.mylearn.designmodel.template;
/** * Created by IntelliJ IDEA. * User: yingkuohao * Date: 13-9-29 * Time: 下午4:43 * CopyRight:360buy * Descrption: * 模板方法:主要是抽象出一个操作流程的骨架,然后把具体的逻辑放入到子类中去。 * 场景:当一个流程的主要流程都相似,都是经过几步共同的操作,就可以先定义出所经历的步骤,然后把骨架流程写成一个 * 方法,供客户端调用。把 * To change this template use File | Settings | File Templates. */ public abstract class AbstractFridge {
/** * 定义模板类的骨架,核心方法,相当于一个模板,描述好这个类及其子类要做一个什么事情, * 把公用的方法直接写好,如openDoor,closeDoor。 * 把具体子类的方法抽象出来,让子类去实现,如pushSth。 * * 注意,方法被声明为final,以免子类改进这个算法的顺序。 * @param context */ final void execute(Context context) {
//step1: 打开冰箱门 openDoor(); //step2: 放入东西(大象,或者是其他) pushSth(context); System.out.println("这次放入冰箱的是:" + context.getName()); //step3: 关上冰箱门 closeDoor(); if(hook()) { System.out.println("hookexecute"); } }
/** * 钩子方法,子类可以选择覆盖 * @return */ private boolean hook() { return true; //To change body of created methods use File | Settings | File Templates. }
/** * 私有方法,子类不可动 */ private void openDoor() { System.out.println("open the door of the fridge!"); }
/** * 抽象方法,子类必须实现:往冰箱里放东西 */ protected abstract void pushSth(Context context);
private void closeDoor() { System.out.println("close the door of the fridge!"); } } |
ElephantFridge:子类——装大象的冰箱
public class ElephantFridge extends AbstractFridge { @Override public void pushSth(Context context) { context.setName("elephant"); } } |
EggFridge:子类——装鸡蛋的冰箱
public class EggFridge extends AbstractFridge { @Override public void pushSth(Context context) { context.setName("egg"); } } |
Client:客户端信息
public class Client { public static void main(String args[]) { Context context = new Context();
AbstractFridge abstractFridge = new ElephantFridge(); abstractFridge.execute(context); } } |
Context: 上下文对象
public class Context { private String name;
public Context(String name) { this.name = name; }
public Context() {
}
public String getName() { return name; }
public void setName(String name) { this.name = name; } } |
要点:
1. 模板方法定义了算法的步骤,把这些步骤的实现延迟到子类。
2. 模板方法模式为我们提供了一种代码复用的重要技巧
3. 模板方法的抽象类可以定义具体方法、抽象方法和钩子。
4. 抽象方法由子类来实现。
5. 钩子是一种方法,它在抽象类中不做事,或者只做默认的事情,子类可以选择要不要去覆盖它。
6. 为了防止子类改变模板方法中的算法,可以将模板方法声明为final。
7. 好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用低层模块。
8. 你将在真实世界代码中看到模板方法模式的许多变体,不要期待它们全都是一眼就可以被你认出的。
9. 策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
10. 工厂方法是模板方法的一种特殊版本。