Template

模板方法(Template Method)

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

原则

好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
(封装算法块)

类图

Template Pattern

Code

origin

// 这是我们的咖啡类,用来煮咖啡
public class Coffee {
    // 这是我们的咖啡冲泡法
    void prepareRecipe() {
        boilWater();
        brewCoffeeGrinds();
        pourInCup();
        addSugerAndMilk();
    }

    // 煮沸水
    private void boilWater() {
        System.out.println("Boiling water");
    }

    // 冲泡咖啡
    private void brewCoffeeGrinds() {
        System.out.println("Dripping coffee through filter");
    }

    // 把咖啡倒进杯子
    private void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 加糖和奶
    private void addSugerAndMilk() {
        System.out.println("Adding Sugar and Milk");
    }
}

// 这是我们的茶类,用来煮茶
public class Tea {
    void prepareRecipe() {
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }

    // 煮沸水。这个方法和咖啡类完全一样
    private void boilWater() {
        System.out.println("Boiling water");
    }

    // 冲泡茶叶
    private void steepTeaBag() {
        System.out.println("Steeping the tea");
    }

    // 把茶倒进杯子。这个方法和咖啡类完全一样
    private void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 加柠檬
    private void addLemon() {
        System.out.println("Adding Lemon");
    }
}

改进

public abstract class CaffeineBeverage {
    // 现在,用同一个prepareRecipe()方法来处理茶和咖啡。
    // prepareRecipe()方法被声明为final,因为我们不希望子类覆盖这个方法
    // 我们将第2步和第4步泛化成为brew()和addCondiments()
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    // 因为咖啡和茶处理这些方法的做法不同,所以这两个方法必须被声明为抽象,
    // 剩余的东西留给子类去操心
    abstract void addCondiments();
    abstract void brew();

    public void boilWater() {
        System.out.println("Boiling water");
    }

    public void pourInCup() {
        System.out.println("Pouring into cup");
    }
}

// 自行处理冲泡和添加调料部分:
public class Coffee extends CaffeineBeverage {
    @Override
    void brew() {
        System.out.println("Dripping coffee through filter");
    }

    @Override
    void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
}

public class Tea extends CaffeineBeverage {
    @Override
    void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    void addCondiments() {
        System.out.println("Adding Lemon");
    }
}

模板方法

// 这就是我们的抽象类。它被声明为抽象,用来作为基类,其子类必须实现其操作
public abstract class AbstractClass {
    // 这就是模板方法。它被声明为final,以免子类改变这个算法的顺序。
    final void templateMethod() {
        // 模板方法定义了一连串的步骤,每个步骤由一个方法代表
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
    }

    // 在这个范例中有两个原语操作,具体子类必须实现它们
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();

    // 这个抽象类有一个具体的操作。
    void concreteOperation() {
        // ...
    }
}

钩子

public abstract class AbstractClass {
    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        // 我们加进一个新方法调用
        hook();
    }

    // 这两个方法还是和以前一样,定义成抽象,由具体的子类实现。
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();

    // 这个具体的方法被定义在抽象类中。
    // 将它声明为final,这样一来子类就无法覆盖它。
    // 它可以被模板方法直接使用,或者被子类使用。
    final void concreteOperation() {
        // ...
    }

    // 我们也可以有“默认不做事的方法”,我们称这种方法为“hook”(钩子)。
    // 子类可以视情况决定要不要覆盖它们。在下面,我们就会知道钩子的实际用途
    void hook() {}
}

Reference

http://cashow.github.io/head-first-design-patterns-notes-template-method-pattern.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值