《HeadFirst设计模式》读书笔记-第8章-模板方法模式

定义

模板方法模式(template method pattern)在一个方法中定义一个算法的骨架,而将一些步骤延时到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

这里写图片描述

下面给出了该类图的代码实现和说明:

public abstract class AbstractClass {
    /**
     * 这个是个模板方法
     * 声明为final是为了防止子类覆盖,以免子类改变这个算法的顺序和结构
     */
    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }

    /**
     * 算法中的步骤,子类根据实际情况实现具体行为
     */
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();

    /**
     * 算法中的步骤
     * 声明为final是为了防止子类覆盖
     */
    final void concreteOperation() {
        // 这里是具体实现
    }

    /**
     * 模板方法定义的钩子
     * 钩子的存在让子类有能力在算法的一些重要时间点被通知,并可以去实现一些功能
     * 子类根据需要决定是否实现钩子
     */
    void hook() {   
    }

}

模板方法中钩子和抽象方法的区分:

  • 抽象方法是算法中不可缺少的,非常重要的步骤,子类必须实现。

  • 钩子是可选的,子类自由选择是否实现。

    钩子的存在有两个目的:

    • 对算法中不重要的,可选的细节让子类进行实现,也可以不实现,使用默认的行为

    • 通知算法执行时间节点的发生,类似回调函数

代码实现

我们看看JDK是如何用模板方法来实现数组的排序的。

首先给出需要排序的对象类型,实现Comparable接口:

public class Duck implements Comparable {
    String name;
    int weight;

    public Duck(String name, int weight) {
        this.name = name;
        this.weight = weight;
    }

    public String toString() {
        return name + " weighs " + weight;
    }
        // Comparable接口中的方法,定义了如何实现Duck对象的比较    
    public int compareTo(Object object) {

        Duck otherDuck = (Duck) object;

        if (this.weight < otherDuck.weight) {
            return -1;
        } else if (this.weight == otherDuck.weight) {
            return 0;
        } else { // this.weight > otherDuck.weight
            return 1;
        }
    }
}

测试代码:

import java.util.ArrayList;
import java.util.Arrays;

public class DuckSortTestDrive {

    public static void main(String[] args) {
        Duck[] ducks = { 
                        new Duck("Daffy", 8), 
                        new Duck("Dewey", 2),
                        new Duck("Howard", 7),
                        new Duck("Louie", 2),
                        new Duck("Donald", 10), 
                        new Duck("Huey", 2)
         };

        Arrays.sort(ducks);
    }
}

继续看Arrays的sort()方法的实现,会发现最终由下面代码片段实现排序:

/**
 * 排序dest[low:high]中的对象
 * compareTo()方法正是我们Duck对象实现的方法,
 * swap()是由Arrays类实现的方法,
 */
for (int i=low; i<high; i++)
    for (int j=i; j>low &&
      ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
        swap(dest, j, j-1);

这个模板方法和我们类图中的不大一样,差别在于标准的模板方法是定义了一个算法的框架,有子类实现某些具体的步骤。而这里没有用到继承,这是因为Array类的sort()方法的设计者收到一些约束:

他希望sort()方法适用于所有的数组,而每个数组都是不同的类,所以无法设计一个类继承Java数组。

所以他把sort()方法定义成静态方法,由被排序的数组元素对象实现Comparable接口,实现对象的比较动作,这个比较的方式可能每个类不一样。swap()实现数组元素的交换,属于通用的方法,所以由Array类实现。

所以上面的描述,sort()方法的设计符合模板方法模式的核心思想:定义了一个算法的框架,有具体类实现某些具体的步骤。

该模式体现了哪些OO原则

本章总结

  1. 模板方法模式为我们提供了一种代码复用的重要技巧

  2. 真实世界中有很多模板方法模式的变体,不一定都是标准的,比如Array.sort()方法

  3. 策略模式和模板方法模式都是封装算法的,策略模式使用组合,模板方法模式使用的是继承

  4. 策略模式封装了完整的算法,模板方法只提供了算法的框架,需要具体类去实现某些步骤

  5. 工厂方法是模板方法的一种特殊版本,用于对象的创建

  6. 好莱坞原则告诉我们,将决策权放在高层模块中,以便决定如何以及何时调用底层模块

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值