【设计模式】行为型-模板方法模式

方法千变万化,心灵如潮,模板如画,画出生活的韵味。

一、茶与咖啡

场景假设:我们需要完成茶和咖啡的制作。

// 咖啡类
class Coffee {
    // 准备配方的方法
    void prepareRecipe() {
        boilWater(); // 煮沸水
        brewCoffeeGrinds(); // 冲泡咖啡
        pourInCup(); // 倒入杯子
        addSugarAndMilk(); // 添加糖和牛奶
    }

    // 下面是每个步骤的具体实现
    void boilWater() { System.out.println("Boiling water"); }
    void brewCoffeeGrinds() { System.out.println("Dripping Coffee through filter"); }
    void pourInCup() { System.out.println("Pouring into cup"); }
    void addSugarAndMilk() { System.out.println("Adding Sugar and Milk"); }
}

// 茶类
class Tea {
    // 准备配方的方法
    void prepareRecipe() {
        boilWater(); // 煮沸水
        steepTeaBag(); // 浸泡茶包
        pourInCup(); // 倒入杯子
        addLemon(); // 添加柠檬
    }

    // 下面是每个步骤的具体实现
    void boilWater() { System.out.println("Boiling water"); }
    void steepTeaBag() { System.out.println("Steeping the tea"); }
    void pourInCup() { System.out.println("Pouring into cup"); }
    void addLemon() { System.out.println("Adding Lemon"); }
}

咖啡和茶创建两个不同的类,并在每个类中实现整个制作过程。这将导致大量的代码重复,因为煮沸水和倒入杯子的步骤对于咖啡和茶来说都是相同的。在这个例子中,boilWaterpourInCup 在两个类中都是重复的。如果我们需要修改这些步骤的实现,我们需要在两个类中都进行修改,这就增加了维护的复杂性。此外,如果我们需要添加一个新的饮料类型,我们又需要复制大量的代码。

二、模板方法模式

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将算法的某些步骤延迟到子类中实现。这样可以在不改变算法结构的情况下,允许子类重新定义算法中的特定步骤。

该模式提供了一个模板(即抽象类),其中包含了一系列的方法,其中某些方法是抽象的,需要由子类实现,而其他方法是具体的,并且已经实现好了。这样,当客户端调用模板方法时,将按照模板的定义来执行一系列的步骤,其中部分步骤可能在子类中有不同的实现。

三、模板方法模式的核心组成

模板方法模式的核心组件主要包括以下几个部分:

  1. 抽象类(Abstract Class):这个类定义了一系列的方法,包括具体的方法(实现了特定功能)和抽象的方法(没有具体实现,需要子类来提供实现)。此外,抽象类还定义了一个模板方法,这个方法按照特定的顺序调用上述的一系列方法。
  2. 具体类(Concrete Class):这个类继承自抽象类,并提供抽象方法的具体实现。当模板方法被调用时,这些具体的实现将被执行。
  3. 模板方法(Template Method):在抽象类中定义,这个方法包含了一个算法的骨架。它按照特定的顺序调用一系列的方法。其中一些方法是具体的,由抽象类提供实现;另一些方法是抽象的,由具体类提供实现。
  4. 钩子方法(Hook Method):这是一种特殊的方法,它在抽象类中通常没有做任何事或者只提供默认的实现,但是它提供了一个扩展点,允许子类在必要时覆盖它。

在这里插入图片描述

在这个类图中:

  1. AbstractClass 是一个抽象类,它定义了 templateMethod()(模板方法)和两个抽象方法 primitiveOperation1() 和 primitiveOperation2()。模板方法定义了一个算法的骨架,按照特定的顺序调用一系列的方法。其中一些方法是具体的,由抽象类提供实现;另一些方法是抽象的,由具体类提供实现。
  2. ConcreteClass 是一个具体类,它继承自 AbstractClass 并提供抽象方法的具体实现。当模板方法被调用时,这些具体的实现将被执行。

四、运用模板方法模式

场景假设:我们需要制作茶、咖啡等多种饮料。

  1. 定义抽象类:首先,我们需要定义一个抽象类,这个类包含了制作饮料的通用步骤。

    // 抽象类:含有咖啡因的饮料
    abstract class CaffeineBeverage {
        // 这是我们的模板方法。它定义了算法的步骤。
        final void prepareRecipe() {
            boilWater(); // 第一步:煮沸水
            brew(); // 第二步:冲泡。但是我们并不知道是冲泡咖啡还是茶,所以这是一个抽象方法。
            pourInCup(); // 第三步:倒入杯子
            addCondiments(); // 第四步:添加调料。但是我们并不知道是添加什么调料,所以这是一个抽象方法。
        }
    
        // 这两个方法是抽象的,也就是说,我们需要子类来提供具体的实现。
        abstract void brew();
        abstract void addCondiments();
    
        // 这两个方法是具体的,也就是说,它们在所有子类中都是一样的,所以我们可以将它们的实现放在这个抽象类中。
        void boilWater() { System.out.println("Boiling water"); }
        void pourInCup() { System.out.println("Pouring into cup"); }
    }
    

    在这个抽象类 CaffeineBeverage 中,我们定义了一个模板方法 prepareRecipe(),它按照特定的顺序调用一系列的步骤。其中 brew() 和 addCondiments() 是抽象的,我们需要子类来提供具体的实现。

  2. 定义具体类:然后,我们为每种饮料定义一个具体的类,这个类继承自抽象类,并提供抽象方法的具体实现。

    // 具体类:咖啡
    class Coffee extends CaffeineBeverage {
        // 对于咖啡来说,冲泡就是用热水过滤咖啡
        void brew() {
            System.out.println("Dripping Coffee through filter");
        }
    
        // 对于咖啡来说,添加的调料是糖和牛奶
        void addCondiments() {
            System.out.println("Adding Sugar and Milk");
        }
    }
    
    // 具体类:茶
    class Tea extends CaffeineBeverage {
        // 对于茶来说,冲泡就是用热水浸泡茶叶
        void brew() {
            System.out.println("Steeping the tea");
        }
    
        // 对于茶来说,添加的调料是柠檬
        void addCondiments() {
            System.out.println("Adding Lemon");
        }
    }
    

    在这两个具体类 Coffee 和 Tea 中,我们提供了 brew() 和 addCondiments() 方法的具体实现。当模板方法 prepareRecipe() 被调用时,这些具体的实现将被执行。

五、模板方法模式的应用场景

模板方法模式通常在以下情况下使用:

  1. 算法框架固定,但具体实现可变:当一个算法的框架已经确定,但其中的一些步骤的具体实现可能会随着应用场景的变化而变化时,可以使用模板方法模式。这样,可以将算法的框架定义在抽象模板中,而将可变的部分留给子类来实现。
  2. 避免代码重复:当多个类中存在相似的算法流程,但具体步骤略有不同,为避免代码重复,可以将这些公共部分提取到抽象模板中,从而避免代码重复,提高代码的复用性。
  3. 提供算法定制化的扩展点:模板方法模式提供了一种在不改变算法结构的情况下,允许子类重新定义算法中特定步骤的方法。这样,可以为客户端提供一种定制化的扩展点,允许客户端根据需要定制算法的具体实现。
  4. 框架设计:模板方法模式在框架设计中也经常被使用,例如在 Web 框架中,可以定义一个抽象的控制器类作为模板,其中包含了请求处理的流程,而具体的控制器类则根据具体业务需求来实现这些步骤。

六、小结

模板方法模式能够帮助我们定义算法的骨架,并允许子类定制算法的具体实现,从而提高了代码的复用性和灵活性,是一种非常有用的设计模式。在实际开发中,我们可以根据具体情况来灵活运用模板方法模式,提高代码的可维护性和扩展性。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await
  • 46
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值