**

**板方法模式的定义:

定义一个操作的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的框架即可重定义该算法的某些特定步骤。

例子:做一个简单的悍马车的模型

见UML图
设计模式之禅——模板方法模式&钩子方法-风君雪科技博客

一个抽象悍马模型类 HummerModel,然后有两个悍马具体型号的实现
类。见代码

public abstract class HummerModel {

    //发动了
    protected abstract void start();
    //停下了
    protected abstract void stop();
    //喇叭发出声音了
    protected abstract void alarm();
    //引擎也开始响了
    protected abstract void engineBoom();
    public final void run(){
        this.start();
        this.engineBoom();
        this.alarm();
        this.stop();
    }
}
public class HummerH1Model extends HummerModel {

    @Override
    protected void start() {
        System.out.println("悍马H1发动");
    }

    @Override
    protected void stop() {
        System.out.println("悍马H1停车");
    }

    @Override
    protected void alarm() {
        System.out.println("悍马H1鸣笛");
    }

    @Override
    protected void engineBoom() {
        System.out.println("悍马H1引擎发出声响");
    }

}
public class HummerH2Model extends HummerModel{

    @Override
    protected void start() {
        System.out.println("悍马H2发动");
    }

    @Override
    protected void stop() {
        System.out.println("悍马H2停车");
    }

    @Override
    protected void alarm() {
        System.out.println("悍马H2鸣笛");
    }

    @Override
    protected void engineBoom() {
        System.out.println("悍马H2引擎发出声响");
    }

}

ok,模板方法模式体现在哪里呢?注意它的定义:定义一个操作的算法的框架。很明显,抽象类中的run方法就是这个算法的框架,也就是模板。

模板方法模式就是如此简单~ 我们来看一下它的通用模板

public abstract class AbstractClass{
    //基本方法
    protected abstract void doSomething();
    //基本方法
    protected abstract void doAnything();
    //模板方法
    public final void tempeteMethod(){
        this.doSomething();
        this.doAnything();
    }
}
public class ConcreteClass1 extends AbstractClass{
    protected void doAnything(){
        //逻辑处理
    }
    protected void doSomething(){
        //逻辑处理
    }
}
public class ConcreteClass2 extends AbstractClass{
    protected void doAnything(){
        //逻辑处理
    }
    protected void doSomething(){
        //逻辑处理
    }
}

模板方法模式的优点

封装不变的内容,扩展可变部分,如果我们要添加一个H3悍马模型,只需要继承父类就可以了。
提取公共部分代码,便于维护
行为由父类控制,子类实现。基本方法是由子类实现的,因此子类可以通过拓展的方法增加相应的功能,符合开闭原则。

模板方法模式的使用场景

多个子类有公有的方法,并且逻辑基本相同时
重复、复杂的算法,可以把核心算法设计为模板方法,周边的细节则有各个子类实现

代码重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后用钩子方法(见下面的”模板方法拓展“)约束其行为。

模板方法模式的拓展(钩子方法)

上面的代码有个问题,喇叭是默认响的,人不能控制,怎么完善呢?

注意!钩子方法应该是最开始设计就有的,而不是去完善、纠正错误的

public abstract class HummerModel {
    //是否能发动
    protected boolean isAlarm() {
        return false;
    }
    //发动了
    protected abstract void start();
    //停下了
    protected abstract void stop();
    //喇叭发出声音了
    protected abstract void alarm();
    //引擎也开始响了
    protected abstract void engineBoom();
    public final void run(){
        this.start();
        this.engineBoom();
        if(this.isAlarm()){
            this.alarm();
        }
        this.stop();
    }
}
public class HummerH1Model extends HummerModel {

    private boolean alarmFlag = true;
    public void setAlarm(boolean isAlarm){
        alarmFlag = isAlarm;
    }
    @Override
    protected boolean isAlarm(){
        return this.alarmFlag;
    }
    @Override
    protected void start() {
        System.out.println("悍马H1发动");
    }

    @Override
    protected void stop() {
        System.out.println("悍马H1停车");
    }

    @Override
    protected void alarm() {
        System.out.println("悍马H1鸣笛");
    }

    @Override
    protected void engineBoom() {
        System.out.println("悍马H1引擎发出声响");
    }

}

虽然这里有模板方法,但是通过钩子方法我们还是能够影响到模板方法的执行(不是影响它的逻辑)。钩子方法在我们平时的编程过程中也是非常常见的。

钩子函数总结

钩子方法源于设计模式中模板方法模式,模板方法模式中分为两大类:模版方法和基本方法,而基本方法又分为:抽象方法,具体方法,钩子方法。

当然这里不细说模板方法模式,对于钩子方法,是对于抽象方法或者接口中定义的方法的一个空实现,在实际中的应用,比如说有一个接口,这个接口里有7个方法,而你只想用其中一个方法,那么这时,你可以写一个抽象类实现这个接口,在这个抽象类里将你要用的那个方法设置为abstract,其它方法进行空实现,然后你再继承这个抽象类,就不需要实现其它不用的方法,这就是钩子方法的作用。