设计模式系列----模板方法模式理解

什么是模板方法模式

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤.

模板方法的使用场景

当两个类相似度极高,除了一两个方法不相同,其他的所有方法都相同时,可以通过模板方法,将相似的方法抽取出来,在抽象父类实现,不相似的方法使用abstrat修饰,强迫子类自己分别实现不相似的方法。相同的方法在父类实现了。

代码例子:
抽象父类

//豆浆类,抽象类
public abstract class SoyaMilk {
    //这是模板方法,用final修饰,不允许子类覆盖。模板方法定义了制作豆浆的程序
    final void  prepareRecipe(){
        selectMaterial();
        addCondiments();
        soak();
        beat();
    }
 
    //选材方法,选择黄豆
    void selectMaterial(){
         System.out.println("第一步、选择好了新鲜黄豆");
    }
 
    //可以添加不同的配料,在这里设置为抽象方法,子类必须实现
    abstract void addCondiments();
 
    //浸泡
    void soak(){
        System.out.println("第三步、黄豆和配料开始浸泡,大概需要5个小时");
    }
 
    //放到豆浆机打碎
    void beat(){
        System.out.println("第四步、黄豆的配料放到豆浆机打碎");
    }
 
}

制作红枣豆浆

//红枣豆浆
public class ReddatesSoyaMilk extends SoyaMilk{
    //实现父类的添加配料方法
    @Override
    void addCondiments() {
        System.out.println("第二步、添加红枣配料");
 
    }
 
}

制造核桃豆浆

 
//核桃豆浆
public class NutSoyaMilk extends SoyaMilk{
    //实现父类的添加配料方法
    @Override
    void addCondiments() {
        System.out.println("第二步、添加核桃配料");      
    }
 
}

测试制作豆浆

public class SoyaMilkTest {
    public static void main(String[] args){
        //制作红枣豆浆
        System.out.println();
        System.out.println("-----制作红枣豆浆步骤-------");
        SoyaMilk reddatesSoyaMilk = new ReddatesSoyaMilk();
        reddatesSoyaMilk.prepareRecipe();
 
        //制作核桃豆浆
        System.out.println();
        System.out.println("-----制作核桃豆浆步骤-------");
        SoyaMilk nutSoyaMilk = new NutSoyaMilk();
        nutSoyaMilk.prepareRecipe();
 
    }
}

在这里插入图片描述
如果后续还要制作其他豆浆,只需要定义一个子类继承父类并实现抽象方法即可,符合开闭原则

钩子方法

并且模板方法模式中,还有钩子方法的概念:
钩子方法的作用

1、让子类实现算法中的可选部分。算法中的某些步骤是可选的,子类可以做出决定是否需要这些步骤。

2、如果钩子对于子类的实现不重要时,子类可以对钩子置之不理。

3、钩子可以让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应。可以在钩子中实现我们对于某个步骤执行需要作出的动作,模板方法的某个步骤执行时,调用钩子。

我们对方法进行改造

1、创建有钩子方法的父类

//豆浆类,抽象类
public abstract class SoyaMilkWithHook {
    //这是模板方法,用final修饰,不允许子类覆盖。模板方法定义了制作豆浆的程序
    final void  prepareRecipe(){
        selectMaterial();
        //判断是否添加配料
        if(customerWantsCondiments()){
            addCondiments();
        }      
        soak();
        beat();
    }
 
    //选材方法,选择黄豆
    void selectMaterial(){
         System.out.println("选择好了新鲜黄豆");
    }
 
    //可以添加不同的配料,在这里设置为抽象方法,子类必须实现
    abstract void addCondiments();
 
    //浸泡
    void soak(){
        System.out.println("材料开始浸泡,大概需要5个小时");
    }
 
    //放到豆浆机打碎
    void beat(){
        System.out.println("材料放到豆浆机打碎");
    }
 
    //钩子方法,是否添加配料
    boolean customerWantsCondiments(){
        return true;
    }
}

2、创建纯豆浆子类

//制作纯豆浆,不添加任何配料
public class PureSoyaMilk extends SoyaMilkWithHook{
 
    @Override
    void addCondiments() {
 
    }
 
    //覆盖钩子方法,不添加配料
    @Override
    boolean customerWantsCondiments(){
        return false;
    }
}

3、测试制作纯豆浆

public class PureSoyaMilkTest {
    public static void main(String[] args){
        //制作纯豆浆
        System.out.println();
        System.out.println("-----制作纯豆浆步骤-------");
        SoyaMilkWithHook pureSoyaMilk = new PureSoyaMilk();
        pureSoyaMilk.prepareRecipe();
    }
}

实现了某些步骤可选

–我是“道祖且长”,一个在互联网"苟且偷生"的Java程序员
“有任何问题,可评论,我看到就会回复”

posted @   道祖且长  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示