前语

看到规划形式中的模板形式(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 class FruitFactory {
    public AbstractFruit getInstance(String fruit) {
        if (fruit == null) {
            return null;
        }
        if (fruit.equalsIgnoreCase("Apple")) {
            return new Apple();
        } else if (fruit.equalsIgnoreCase("Banana")) {
            return new Banana();
        } else if (fruit.equalsIgnoreCase("Watermelon")) {
            return new Watermelon();
        }
        return null;
    }
}
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的


感谢阅览~不喜勿喷。欢迎评论、指正