当前位置: 首页 > article >正文

设计模式-模板方法

模板方法(Template Method)是行为型设计模式的一种,它在一个抽象类中定义了一个算法的骨架,而将算法的一些步骤延迟到子类中实现。通过这种方式,模板方法使得子类可以在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

适用场景:
  • 算法步骤固定,但部分实现可变:当一个算法的整体流程是确定的,但其中某些步骤的实现是可变的。
  • 代码复用:通过将公共的代码上移到抽象类中,减少重复代码。
  • 控制子类扩展:通过在抽象类中定义模板方法,控制算法的执行流程,防止子类改变算法的顺序。
结构:
  • 抽象类(AbstractClass):定义算法的骨架,包括模板方法和基本方法。

    • 定义了模板方法 templateMethod(),该方法按照一定的顺序调用基本方法。模板方法一般是 final 的,以防止子类改变算法的流程。
    • 包含若干个基本方法 primitiveOperation(),可以是抽象的,也可以有默认实现。
  • 具体类(ConcreteClass):实现抽象类中的抽象方法,完成算法中可变的部分。

示例:

以制作饮料(咖啡和茶)为例:

1. 抽象类:Beverage

public abstract class Beverage {

    // 模板方法,定义了制作饮料的流程
    public final void prepareRecipe() {
        boilWater();
        brew();              // 抽象方法,由子类实现
        pourInCup();
        addCondiments();     // 抽象方法,由子类实现
    }

    // 基本方法,所有子类共有
    private void boilWater() {
        System.out.println("烧开水");
    }

    // 基本方法,所有子类共有
    private void pourInCup() {
        System.out.println("倒入杯中");
    }

    // 抽象方法,子类需要实现
    protected abstract void brew();

    // 抽象方法,子类需要实现
    protected abstract void addCondiments();
}

2. 具体类:Tea(茶)

public class Tea extends Beverage {

    @Override
    protected void brew() {
        System.out.println("浸泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("添加柠檬");
    }
}

3. 具体类:Coffee(咖啡)

public class Coffee extends Beverage {

    @Override
    protected void brew() {
        System.out.println("冲泡咖啡");
    }

    @Override
    protected void addCondiments() {
        System.out.println("添加糖和牛奶");
    }
}

4. 测试类

public class Client {
    public static void main(String[] args) {
        Beverage tea = new Tea();
        tea.prepareRecipe();

        System.out.println("-----------------");

        Beverage coffee = new Coffee();
        coffee.prepareRecipe();
    }
}

5. 运行结果

烧开水
浸泡茶叶
倒入杯中
添加柠檬
-----------------
烧开水
冲泡咖啡
倒入杯中
添加糖和牛奶
钩子方法(Hook)的应用

有时,我们希望子类能够控制算法的某些步骤是否执行,可以使用钩子方法:

1. 修改抽象类

public abstract class BeverageWithHook {

    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) { // 钩子方法,决定是否添加调料
            addCondiments();
        }
    }

    private void boilWater() {
        System.out.println("烧开水");
    }

    private void pourInCup() {
        System.out.println("倒入杯中");
    }

    protected abstract void brew();

    protected abstract void addCondiments();

    // 钩子方法,默认返回 true,子类可根据需要重写
    protected boolean customerWantsCondiments() {
        return true;
    }
}

2. 修改具体类

public class TeaWithHook extends BeverageWithHook {

    @Override
    protected void brew() {
        System.out.println("浸泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("添加柠檬");
    }

    @Override
    protected boolean customerWantsCondiments() {
        // 例如,根据用户输入决定是否添加调料
        return getUserInput().equalsIgnoreCase("y");
    }

    private String getUserInput() {
        // 模拟用户输入,实际应用中可使用 Scanner 等获取输入
        return "n";
    }
}

3. 测试结果

烧开水
浸泡茶叶
倒入杯中
设计原则:
  • 好莱坞原则:不要调用我们,我们会调用你(Don’t call us, we’ll call you)。在模板方法中,父类调用子类实现的方法,而不是子类控制流程

  • 开闭原则:模板方法模式使得算法的结构对扩展开放,对修改封闭。可以通过新增子类来扩展新的行为,而无需修改抽象类。

优点:
  • 代码复用:将公共的代码提取到抽象类中,减少重复代码。
  • 灵活性高:子类可以根据需要实现算法的可变部分。
  • 控制流程:通过模板方法,统一算法的执行步骤,控制算法的流程。
缺点:
  • 类数量增加:每个不同的实现都需要一个子类,可能会导致类的数量增加。
  • 继承的局限:由于模板方法依赖于继承,灵活性受到限制,子类只能重写父类的方法,不能修改模板方法本身。
实际应用:
  • Java 中的 AbstractListAbstractSet 等抽象类:提供了集合的模板实现,子类只需实现特定的方法。
  • Servlet 中的 HttpServlet:通过 doGet()doPost() 等方法,由子类实现具体的请求处理。

http://www.kler.cn/news/356106.html

相关文章:

  • SQL基础练习题三
  • 极氪汽车困局:营销频繁车、产品力不足
  • 群晖通过 Docker 安装 MySQL
  • 文心一言帮程序员干活:请帮我写出数字1到50的英文
  • Linux C语言 进程详解——fork()/wait()/waitpid()
  • 河北工业大学《2023年+2022年980自动控制原理真题》 (完整版)
  • Docker国内设置镜像最新加速地址
  • ddos攻击介绍和排查方法
  • 冲锋衣市场洞察:全方位数据分析与趋势展望
  • 深入解析浮动布局及其在现代Web开发中的应用与替代(浮动的概念及应用、如何清除浮动、使用Flex布局和Grid布局的区别、使用`float`布局的历史和现状)
  • c++ std::future 和 std::promise 的实现工作原理简介
  • 获取非加密邮件协议中的用户名和密码——安全风险演示
  • 操作系统任务操作
  • CTFHUB技能树之SQL——Refer注入
  • 滚雪球学Redis[6.4讲]:Redis消息队列:构建高效的消息通信与任务调度系统
  • PyTorch 的 Dataset 类介绍
  • 构建行业应用生态:云原生应用市场简化企业软件安装
  • 【ChatGPT】如何让 ChatGPT 理解多步骤指令
  • 使用Riotee轻松实现无电池TinyML
  • .net 根据html的input type=“week“控件的值获取星期一和星期日的日期