likes
comments
collection
share

模板模式核心 - 钩子方法详解

作者站长头像
站长
· 阅读数 14

前言

看到设计模式中的模板模式(Template Pattern),激动了

这题我会

模板模式定义👇

一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行

这核心不就是钩子方法嘛,我开发的时候还挺喜欢用的

欸嘿,看我把你说明白了

钩子方法

其实钩子方法的关键实现,在前言里已经说了,再复述一遍:

  1. 抽象类定义抽象方法(钩子)、模板方法(模板方法中调用抽象方法)
  2. 子类重写抽象方法
  3. 调用抽象类的模板方法

啥时候用呢

举个例子吧

有一次我们项目组收到需求,其中有个功能分析下来可以类比成这样:

  1. 苹果削皮吃
  2. 香蕉剥皮吃
  3. 西瓜切开吃

我对实现这个功能的小伙伴说,有成熟的技术大胆用,咱们总要进步的嘛

CodeReview的时候看到他整了个工厂模式

不错👏,听进去了

大致是这么写的

public abstract class AbstractFruit {
    public abstract void eat();
}

public class Apple extends AbstractFruit {
    @Override
    public void eat() {
        System.out.println("削皮吃");
    }
}

public class Banana extends AbstractFruit {
    @Override
    public void eat() {
        System.out.println("剥皮吃");
    }
}

public class Watermelon extends AbstractFruit {
    @Override
    public void eat() {
        System.out.println("切开吃");
    }
}

public static void main(String[] args) {
    FruitFactory fruitFactory = new FruitFactory();
    AbstractFruit fruit = fruitFactory.getInstance("Apple");
    fruit.eat();
}

后来有一天需求变了,“水果吃之前要洗一洗”

他说还行,改改 Apple、Banana、Watermelon 里的 eat() 就行

我说不用,改成钩子方法吧,省得用户“吃完水果还要扔垃圾”

他说啥叫钩子方法?

我说,你这样改

public abstract class AbstractFruit {
    // 模板方法
    public void eatFruit() {
        // 通用逻辑
        System.out.println("洗一洗");
        // 模板方法调用钩子方法
        this.eat();
    }

    // 钩子方法
    public abstract void eat();
}

public static void main(String[] args) {
    FruitFactory fruitFactory = new FruitFactory();
    AbstractFruit fruit = fruitFactory.getInstance("Apple");
    // 注意,这里由eat()改为了eatFruit()
    fruit.eatFruit();
}

只能是抽象类、抽象方法吗

先说结论:不是。但得用Java8及以上版本

Java8新增了接口的默认方法

简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法

所以说还可以用接口

public interface IFruit {
    default void eatFruit() {
        System.out.println("洗一洗");
        this.eat();
    }

    void eat();
}

public class Apple implements IFruit {
    @Override
    public void eat() {
        System.out.println("削皮吃");
    }
}

public class Banana implements IFruit {
    ...
}

public class Watermelon implements IFruit {
    ...
}

public static void main(String[] args) {
    FruitFactory fruitFactory = new FruitFactory();
    IFruit fruit = fruitFactory.getInstance("Apple");
    fruit.eatFruit();
}

总结

通过例子我们可以看到当整体逻辑相同、部分逻辑有差异时,可以考虑使用钩子方法

另外说点题外话

我认为在开发时不用生搬硬套设计模式,没用到设计模式也不必妄自菲薄。开发是对需求的实现,跟着需求变化产出的代码就好。就像文中的例子,如果需求没变,那么工厂模式是完全OK的;如果“用户只吃一种水果”,那么不用工厂模式和钩子方法也是完全OK的


感谢阅读,不喜勿喷。欢迎讨论、指正