Hook Method
钩子方法(Hook Method)之所以被称为“钩子”,是因为它在算法或流程中提供了一个“钩子”,允许子类在特定的点上“钩入”自己的实现逻辑,从而影响算法的行为或流程的执行。
它类似于一个挂钩、锚点,所以叫Hook method, 它允许子类插入自定义的代码来改变或扩展算法的功能。
Template pattern 的实现就必须用到Hook method。
Hook Method一般在抽象类中被定义,但默认情况下没有实现或者提供一个空实现。
钩子方法的作用是允许具体子类有选择地覆盖或扩展算法的某些步骤。
What is Template
模板模式(Template Pattern)是一种行为设计模式,它定义了一个操作中的算法骨架,将一些步骤推迟到子类中实现。模板模式使得子类可以在不改变算法结构的情况下,重新定义算法中的特定步骤。
它提供了一种灵活的方式,允许子类定制算法的特定部分,同时保持整体的一致性。
Compare between Template and Builder
模板模式适用于具有相似算法结构但具体步骤有所不同的场景。它提供了一种灵活的方式,允许子类定制算法的特定部分,同时保持整体的一致性。
建造者模式适用于创建对象的构建过程比较复杂,需要一步一步地进行,并且需要创建不同表示的情况。
Key Elements
- 抽象类(Abstract Class)
抽象类定义了算法的骨架,包含了一个或多个抽象方法或钩子(hook)方法,这些方法将在具体子类中实现。抽象类还可以包含具体方法来定义算法的通用步骤,这些步骤可以被子类直接使用或覆盖。 - 具体类(Concrete Class)
具体类是抽象类的子类,它实现了由抽象类定义的抽象方法或钩子方法,并为算法中的特定步骤提供了具体的实现。
Simple Example
当你使用咖啡机制作咖啡时,可以使用模板模式来定义制作咖啡的算法骨架,同时允许子类来定制特定步骤的实现。
// 模板类 - 制作咖啡的算法骨架
public abstract class CoffeeMaker {
public void makeCoffee() {
boilWater();
brewCoffee();
pourInCup();
addMilkAndSugar();
}
public void boilWater() {
System.out.println("Boiling water");
}
// 抽象方法,由子类实现
public abstract void brewCoffee();
public void pourInCup() {
System.out.println("Pouring coffee into cup");
}
// 钩子方法,子类可以选择性实现
public void addMilkAndSugar() {
// 默认不加牛奶和糖
}
}
// 具体类 - 制作黑咖啡
public class BlackCoffeeMaker extends CoffeeMaker {
@Override
public void brewCoffee() {
System.out.println("Brewing black coffee");
}
}
// 具体类 - 制作拿铁咖啡
public class LatteCoffeeMaker extends CoffeeMaker {
@Override
public void brewCoffee() {
System.out.println("Brewing espresso");
}
@Override
public void addMilkAndSugar() {
System.out.println("Adding milk and sugar");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
CoffeeMaker blackCoffeeMaker = new BlackCoffeeMaker();
blackCoffeeMaker.makeCoffee();
System.out.println("--------------------");
CoffeeMaker latteCoffeeMaker = new LatteCoffeeMaker();
latteCoffeeMaker.makeCoffee();
}
}
在上述示例中,CoffeeMaker 是一个抽象类,定义了制作咖啡的算法骨架。它包含了一系列的步骤:
- 烧水
- 冲泡咖啡
- 倒入杯子中
- 加牛奶和糖(可选)。
其中:
- brewCoffee() 是一个抽象方法,由具体子类实现。
- addMilkAndSugar() 是一个钩子方法,具体子类可以选择性地覆盖该方法。
- BlackCoffeeMaker 是一个具体子类,实现了 brewCoffee() 方法,制作黑咖啡时只冲泡咖啡,不加牛奶和糖。
- LatteCoffeeMaker 是另一个具体子类,实现了 brewCoffee() 方法和 addMilkAndSugar() 方法,制作拿铁咖啡时先冲泡浓缩咖啡,然后加入牛奶和糖。
- Client 在客户端代码中,我们创建了一个黑咖啡机和一个拿铁咖啡机,并调用它们的 makeCoffee() 方法来制作咖啡。由于模板模式的存在,制作咖啡的算法骨架是固定的,但具体的咖啡种类和加料可以由子类来定制。