模板方法模式

1.定义

在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 简单来说就是抽象类中的一个 final 修饰的 方法封装了几个方法,而这些方法需要子类的具体实现,但是总体算法的步骤是抽象类中定义好的.

2.代码实现

这次模拟的是泡咖啡和泡茶两种行为,泡咖啡的步骤是 1.烧开水 2.冲泡咖啡粉 3. 咖啡倒进杯子 4. 加糖和牛奶

泡茶的步骤是 1.烧开水 2. 泡茶叶 3. 把茶倒进杯子 4. 加柠檬

这边相似的动作是 1 烧开水 和 3 倒进杯子  不同的是 一个泡的咖啡,加的是糖和牛奶,另一个是 泡的茶,加的是柠檬. 所以我们可以把 冲泡这个动作和加东西这个动作给抽象出来,具体的实现让子类进行.

这两种行为的步骤都是一致的,所以我们可以用一个抽象类来封装这种步骤.

public abstract class CaffeineBeverage {
    
    /**
     * 封装的步骤
     */
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }
    
    abstract void brew();
    abstract void addCondiments();
    
    void boilWater() {
        System.out.println("Biling water");
    }
    
    void pourInCup() {
        System.out.println("Pouring into cup");
    }
    /**
     * 钩子方法
     * @return
     */
    boolean customerWantsCondiments() {
        return true;
    }
    
}

prepareRecipe 这个方法中 ,我们调用了 烧开水,冲泡,倒进杯子,加调料这四种方法,其中烧开水和倒进杯子这两种方法由抽象类实现,因为都是冲泡饮料相同的动作,不同的实现冲泡和加调料这两种方法,我们可以让具体的子类去实现. 而且prepareRecipe 方法是final类型的,就是防止子类覆盖这个方法修改方法的执行步骤.

customerWantsCondiments 方法是钩子方法,钩子方法在模板方法中可以当作一个条件来让子类决定算法的行为,子类可以选择实现或者选择不实现.

 

我们先定义茶

public class Tea extends CaffeineBeverage{

    @Override
    void brew() {
        System.out.println("Steeping the tea");
    }

    @Override
    void addCondiments() {
        System.out.println("Adding Lemon");
    }
}

茶这边实现了咖啡饮料这个抽象方法, 并且实现了 brew 和 addCondiments 这里两种抽象方法.

 

定义咖啡

public class Coffee extends CaffeineBeverage{

    @Override
    void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    @Override
    void addCondiments() {
        System.out.println("Adding sugar and milk");
    }

    @Override
    boolean customerWantsCondiments() {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        
        if (str.toLowerCase().equals("y")) {
            return true;
        }
        
        return false;
    }
    
    
}

咖啡也实现了 brew 和 addCondiments 这里两种抽象方法. 并且也实现了customerWantsCondiments方法,可以通过舒服 'Y' 或者 'N' 来让用户选择加糖和牛奶或者不加.这就是钩子的一个用途.

 

测试累

public class ModelTest {
    public static void main(String[] args) {
        Tea tea = new Tea();
        tea.prepareRecipe();
        
        System.out.println();
        
        Coffee coffee = new Coffee();
        coffee.prepareRecipe();
    }
}

 

执行结果

Biling water
Steeping the tea
Pouring into cup
Adding Lemon

Biling water
Dripping Coffee through filter
Pouring into cup
Y
Adding sugar and milk

这里输入了 Y 以后才加入了Adding Sugar and mikl

 

3.总结

我们可以看到模板方法主要是通过继承来实现的,在抽象类中定义了一个final方法来规定算法的具体框架,然后算法框架中的具体实现让子类去进行,所以这种需要子类实现的算法可以定义成 abstract 类型.

这里钩子这个方法因为是子类可以选择实现或者选择不实现的方法,所以没必要定义成abstract类型,主要是用来让子类实现这个方法改变算法的一些步骤.

和策略模式不同的是,模板方法是定义算法的框架,而策略模式是通过组合的方式来实现具体的算法.两者定位不同.

这边工厂模式也是通过子类来决定具体生成哪一种工厂模式,并且也是通过继承抽象类的方法来实现,所以也可以把工厂模式当作模板方法的变体.

 

posted @ 2019-07-24 23:24  随意的马蒂洛克  阅读(155)  评论(0编辑  收藏  举报