模板方法模式--钩子方法

前言

  说到模(mú)板,很多人都接触过,C++和Java都有诸如List和Stack这样的模板类。但是说到模板方法,很多人可能说不太清楚,或者虽然在学习工作中接触到了,但是不知道其实它是一种模板方法。

  按照设计模式一书的说法,模板方法模式是将一个算法的一部分逻辑下移给子类去定义和实现。


叙述

  根据上面的说法,一般我们使用抽象类而非接口来进行模板方法的实现。为什么呢?因为是一个算法的一部分逻辑,这说明其中有一部分是父类已经定义并实现的,子类掌握的是部分步骤的重写权限。
  一般来说,我们可以将一个模板方法父类进行如下的定义:

public abstract class AbstractParent{
    //骨架方法
    public void skeleton(){
        concreteMethod();
        hookMethod();
        abstractMethod();
    }

    //具体方法
    public void concreteMethod(){
        System.out.println("Here comes the concrete method.");
    }

    //钩子方法
    public void hookMethod(){}

    //抽象方法
    public abstract void abstractMethod();
}

骨架方法

  主要定义了整个方法需要实现的业务操作的骨架。其中调用不同方法的顺序因人而异,而且这个方法也可以做成一个抽象方法要求子类自行定义逻辑流程。

  其中调用了具体方法、钩子方法、抽象方法,也可以根据实际情况增加其他逻辑或条件等。


具体方法

  一个骨架中,有可能有一些逻辑是确定不变的,这个时候可以直接在父类中定义完全的已实现的方法,无需子类再进行覆盖。


抽象方法

  一个普通的抽象方法,放在这个地方其实也是增强了父类提供给子类的灵活性。


钩子方法

  大家可以看到,这个方法虽然说不是abstract的,但是实现中没有任何语句。这个时候其实我们是想让子类去覆盖(Override)这个方法。


何谓钩子(hook)?

不是由该方法的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

如果某个子类需要在ConcreteMethod方法后,在AbstractMethod方法前进行某些操作,就可以覆盖这个钩子方法,实现自己的逻辑即可,并不需要修改父类或其调用方。
钩子就是在整体流程的设计中,故意留下的供子类灵活变更的钥匙。

钩子是一种被声明在抽象类中的方法,但钩子只有空的或者默认方法实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩由子类自行决定。

当在模板方法中某一些步骤是可选的时候,也就是该步骤不一定要执行,可以由子类来决定是否要执行,则此时就需要用上钩子。钩子是一种被声明在抽象类中的方法,但一般来说它只是空的或者具有默认值,子类可以实现覆盖该钩子,来设置算法步骤的某一步骤是否要执行。钩子可以让子类实现算法中可选的部分,让子类能够有机会对模板方法中某些一即将发生的步骤做出反应。


钩子方法实现方式

方式一

最简单的钩子方法就是空方法,代码如下:

public virtual void Display() { }

当然也可以在钩子方法中定义一个默认的实现,如果子类不覆盖钩子方法,则执行父类的默认实现代码。

方式二

另一种钩子方法可以实现对其他方法进行约束,这种钩子方法通常返回一个 bool 类型,即返回 true 或 false,用来判断是否执行某一个基本方法,下面通过一个实例来说明这种钩子方法的使用。

代码如下:
抽象父类

public abstract class AbstractClass {

    public abstract boolean isOpen();

    public final void operating() {
        if(isOpen()) {
            System.out.println("钩子方法开启");
        }else {
            System.out.println("钩子方法关闭");
        }
    }
}

实现类

public class AchieveClass extends AbstractClass {

  //钩子方法能挂在到operating能干预到operating业务逻辑
    @Override
    public boolean isOpen() {
        return true;
    }

    public static void main(String[] args) {
        AchieveClass ac = new AchieveClass();
        ac.operating();
    }

}

只要重写isOpen就能干预父类方法的业务流程。相当于将isOpen挂载在了父类的operating()中。


小结

钩子顾名思义就是用来挂东西的。那么要挂东西必须有个被挂的东西,要不就是铁环、要不就是墙的边沿。所以要能挂住东西必须要有个被勾住的铁环,要一个钩子。那么在java中也是同样的原理,你首先需要一个被挂在的东西,一个挂载的东西。

感谢您的阅读~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章