设计模式——模板方法模式

模板方法 模式

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

一个例子

假设有咖啡和茶两个类:

public class Coffee {
    void prepareRecipe() {
        // 1. 烧水
        boilWater();
        // 2. 用沸水冲泡咖啡
        brewCoffeeGrinds();
        // 3. 把咖啡倒进杯子
        pourInCup();
        // 4. 加糖和牛奶
        addSugarAndMilk();
    }
    private void addSugarAndMilk() {
        System.err.println("加柠檬");
    }

    private void pourInCup() {
        System.err.println("茶倒入杯子里");
    }

    private void brewCoffeeGrinds() {
        System.err.println("冲泡咖啡");
    }

    private void boilWater() {
        System.err.println("将水煮沸");
    }
}
package com.gitlearning.hanldegit.patterns.template.before;

public class Tea {
    /**
     * 沏茶的整个过程
     */
    void prepareRecipe() {
        // 1. 烧水
        boilWater();
        // 2. 浸泡茶叶(不是越狱中的T-bag哦)
        steepTeaBag();
        // 3. 把茶倒入杯子
        pourInCup();
        // 4. 加柠檬
        addLemon();
    }

    private void addLemon() {
        System.err.println("加柠檬");
    }

    private void pourInCup() {
        System.err.println("茶倒入杯子里");
    }

    private void steepTeaBag() {
        System.err.println("浸泡茶叶");
    }

    private void boilWater() {
        System.err.println("将水煮沸");
    }
}

我们发现沏茶和冲咖啡的过程有些是一样的,有些不一样。

prepareRecipe作为模板方法,抽取一个抽象类:

package com.gitlearning.hanldegit.patterns.template.after;

// 咖啡因饮料
public abstract class CaffeineBeverage {
    void prepareRecipe() {
        // 1. 烧水
        boilWater();
        // 2. 冲泡
        brew();
        // 3. 倒进杯子
        pourInCup();
        // 4. 加料
        addCondiments();
    }

    protected abstract void addCondiments() ;

    private void pourInCup() {
        System.err.println("茶倒入杯子里");
    }

    protected abstract void brew() ;

    private void boilWater() {
        System.err.println("将水煮沸");
    }
}

Caffee和Tea继承该抽象类,并实现各自的brew和addCondiments方法。

package com.gitlearning.hanldegit.patterns.template.after;

public class Coffee extends CaffeineBeverage {
    @Override
    protected void addCondiments() {
        System.err.println("加奶和糖");
    }

    @Override
    protected void brew() {
        System.err.println("冲泡咖啡");
    }
}

package com.gitlearning.hanldegit.patterns.template.after;

public class Tea extends CaffeineBeverage {
    @Override
    protected void addCondiments() {
        System.err.println("加柠檬");
    }

    @Override
    protected void brew() {
        System.err.println("浸泡茶叶");
    }
}

至此,使用模板方法模式解决两个类的冗余代码已经解决。

模板方法的使用

Java中使用到模板方法的地方:

AQS:acquire,release,acquireShared,releaseShared,里面调用子类方法tryAcquire,tryRelease,tryAcquireShared,tryReleaseShared。

InputStream:public int read(byte b[], int off, int len) throws IOException调用了read()方法,read方法由子类实现

其他

  1. github上的patterns.template包下面另外写了个参照AQS的写法,里面新增了beforeExecute()方法和afterExecute()钩子方法,钩子方法可以用来做一些日志记录或者性能测试相关的一些操作。

  2. 模板方法经常用在框架里,超类给定方法,具体实现由子类完成。

  3. 模板方法定义了算法步骤,并将实现延迟到子类

  4. 模板方法提供了一种代码复用的重要技巧

  5. 模板方法抽象类可以定义具体方法/抽象方法/钩子方法,钩子可以不做事,或default,子类可以选择是否覆写

  6. 模板方法模式和策略模式都封装算法,一个用组合,一个用继承

  7. 好莱坞原则:别调用我们,我们会调用你。模板方法的抽象类来调用子类的方法实现。

  8. 工厂方法是模板方法的一种特殊版本。

当你准备好了,机会来临的时候,你才能抓住
原文地址:https://www.cnblogs.com/studentytj/p/11295729.html