行为型设计模式(一)模版方法模式 迭代器模式

news2024/11/17 1:48:55

模板方法模式 Template

1、什么是模版方法模式

模版方法模式定义了一个算法的骨架,它将其中一些步骤的实现推迟到子类里面,使得子类可以在不改变算法结构的情况下重新定义算法中的某些步骤。

2、为什么使用模版方法模式

  1. 封装不变部分:模版方法模式将算法的不变部分封装在父类中,使得子类只需要实现变化的部分,提高了代码的复用性。
  2. 扩展性:子类可以通过重写父类的方法来扩展或修改算法的行为,提高了灵活性。
  3. 避免代码重复:将相同的代码放在父类中,避免了在每个子类中重复相同的代码。

3、如何使用模版方法模式

设计实现一个制作咖啡的场景,其中一些步骤是相同的,而一些不同的步骤可以由子类重写

// 模板类
abstract class CoffeeTemplate {
    // 模板方法,定义咖啡的制作步骤
    final void makeCoffee() {
        boilWater();
        brewCoffeeGrounds();
        pourInCup();
        addCondiments();
    }

    // 具体步骤,煮沸水
    void boilWater() {
        System.out.println("Boiling water");
    }

    // 具体步骤,冲泡咖啡
    void brewCoffeeGrounds() {
        System.out.println("Brewing coffee grounds");
    }

    // 具体步骤,倒入杯中
    void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 具体步骤,添加调料,子类实现
    abstract void addCondiments();
}

// 具体子类,制作茶
class TeaTemplate extends CoffeeTemplate {
    @Override
    void addCondiments() {
        System.out.println("Adding lemon");
    }
}

// 具体子类,制作咖啡
class CoffeeTemplateImpl extends CoffeeTemplate {
    @Override
    void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        CoffeeTemplate tea = new TeaTemplate();
        tea.makeCoffee();

        CoffeeTemplate coffee = new CoffeeTemplateImpl();
        coffee.makeCoffee();
    }
}

4、是否存在缺陷和不足

  1. 限制子类:模版方法模式可能限制了子类的灵活性,因为在这个模式中要求子类必须遵循父类定义的算法骨架。
  2. 难以维护:如果模版方法变得复杂,可能会导致难以维护和理解。

5、如何缓解缺陷和不足

  1. 使用钩子方法:在模版方法中引入钩子方法,允许子类选择性地实现或者覆盖某些步骤,提高灵活性。
// 模板类
abstract class CoffeeTemplate {
    // 模板方法,定义咖啡的制作步骤
    final void makeCoffee() {
        boilWater();
        brewCoffeeGrounds();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }

    // 具体步骤,煮沸水
    void boilWater() {
        System.out.println("Boiling water");
    }

    // 具体步骤,冲泡咖啡
    void brewCoffeeGrounds() {
        System.out.println("Brewing coffee grounds");
    }

    // 具体步骤,倒入杯中
    void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 具体步骤,添加调料,子类实现
    abstract void addCondiments();

    // 钩子方法,决定是否添加调料,默认添加
    boolean customerWantsCondiments() {
        return true;
    }
}

// 具体子类,制作茶
class TeaTemplate extends CoffeeTemplate {
    @Override
    void addCondiments() {
        System.out.println("Adding lemon");
    }

    // 通过重写钩子方法,决定是否添加调料
    @Override
    boolean customerWantsCondiments() {
        // 用户不想要调料
        return false;
    }
}

// 具体子类,制作咖啡
class CoffeeTemplateImpl extends CoffeeTemplate {
    @Override
    void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        CoffeeTemplate tea = new TeaTemplate();
        tea.makeCoffee();

        CoffeeTemplate coffee = new CoffeeTemplateImpl();
        coffee.makeCoffee();
    }
}
// 使用钩子方法 customerWantsCondiments 来判断是否执行添加调料的步骤,然后在 TeaTemplate 中
// 重写钩子方法,用户可以选择是否添加。CoffeeTemplateImpl 中没有重写钩子方法,就默认执行
  1. 使用策略模式:考虑将某些步骤设计成策略对象,允许在运行时切换算法的实现。
// 策略接口,调料的添加策略
interface CondimentsStrategy {
    void addCondiments();
}

// 具体的调料策略,添加柠檬
class LemonCondiments implements CondimentsStrategy {
    @Override
    public void addCondiments() {
        System.out.println("Adding lemon");
    }
}

// 具体的调料策略,添加糖和牛奶
class SugarAndMilkCondiments implements CondimentsStrategy {
    @Override
    public void addCondiments() {
        System.out.println("Adding sugar and milk");
    }
}

// 模板类
abstract class CoffeeTemplate {
    // 策略对象,用于调料的添加
    private CondimentsStrategy condimentsStrategy;

    // 设置调料策略
    void setCondimentsStrategy(CondimentsStrategy condimentsStrategy) {
        this.condimentsStrategy = condimentsStrategy;
    }

    // 模板方法,定义咖啡的制作步骤
    final void makeCoffee() {
        boilWater();
        brewCoffeeGrounds();
        pourInCup();
        addCondiments();
    }

    // 具体步骤,煮沸水
    void boilWater() {
        System.out.println("Boiling water");
    }

    // 具体步骤,冲泡咖啡
    void brewCoffeeGrounds() {
        System.out.println("Brewing coffee grounds");
    }

    // 具体步骤,倒入杯中
    void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 具体步骤,添加调料,通过策略对象调用
    void addCondiments() {
        if (condimentsStrategy != null) {
            condimentsStrategy.addCondiments();
        }
    }
}

// 具体子类,制作茶
class TeaTemplate extends CoffeeTemplate {
    // 构造方法中设置具体的调料策略
    TeaTemplate() {
        setCondimentsStrategy(new LemonCondiments());
    }
}

// 具体子类,制作咖啡
class CoffeeTemplateImpl extends CoffeeTemplate {
    // 构造方法中设置具体的调料策略
    CoffeeTemplateImpl() {
        setCondimentsStrategy(new SugarAndMilkCondiments());
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        CoffeeTemplate tea = new TeaTemplate();
        tea.makeCoffee();

        CoffeeTemplate coffee = new CoffeeTemplateImpl();
        coffee.makeCoffee();
    }
}
// 引入 CondimentsStrategy 策略接口和具体的策略实现类:LemonCondiments 和 SugarAndMilkCondiments
// 如此将调料的添加变成一个可变的部分。在 CoffeeTemplateImpl 中引入策略对象,通过
// setCondimentsStrategy 设置具体的调料策略
  1. 分解大方法:如果模版方法变得复杂,考虑将其分解成多个小方法,使得每个方法都相对简单。
// 模板类
abstract class CoffeeTemplate {
    // 策略对象,用于调料的添加
    private CondimentsStrategy condimentsStrategy;

    // 设置调料策略
    void setCondimentsStrategy(CondimentsStrategy condimentsStrategy) {
        this.condimentsStrategy = condimentsStrategy;
    }

    // 模板方法,定义咖啡的制作步骤
    final void makeCoffee() {
        boilWater();
        brewCoffeeGrounds();
        pourInCup();
        addCondiments();
    }

    // 具体步骤,煮沸水
    void boilWater() {
        System.out.println("Boiling water");
    }

    // 具体步骤,冲泡咖啡
    void brewCoffeeGrounds() {
        System.out.println("Brewing coffee grounds");
    }

    // 具体步骤,倒入杯中
    void pourInCup() {
        System.out.println("Pouring into cup");
    }

    // 具体步骤,添加调料,通过策略对象调用
    void addCondiments() {
        if (condimentsStrategy != null) {
            condimentsStrategy.addCondiments();
        }
    }
}

// 具体子类,制作茶
class TeaTemplate extends CoffeeTemplate {
    // 构造方法中设置具体的调料策略
    TeaTemplate() {
        setCondimentsStrategy(new LemonCondiments());
    }

    // 具体步骤,添加茶叶
    void addTeaLeaves() {
        System.out.println("Adding tea leaves");
    }
}

// 具体子类,制作咖啡
class CoffeeTemplateImpl extends CoffeeTemplate {
    // 构造方法中设置具体的调料策略
    CoffeeTemplateImpl() {
        setCondimentsStrategy(new SugarAndMilkCondiments());
    }

    // 具体步骤,添加咖啡粉
    void addCoffeePowder() {
        System.out.println("Adding coffee powder");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        TeaTemplate tea = new TeaTemplate();
        tea.makeCoffee();
        tea.addTeaLeaves();

        CoffeeTemplateImpl coffee = new CoffeeTemplateImpl();
        coffee.makeCoffee();
        coffee.addCoffeePowder();
    }
}

迭代器模式 Iterator

1、什么是迭代器模式

迭代器模式定义了一种方法来顺序访问一个容器对象中的各个元素,而不需要暴露该对象的内部细节,把对元素的访问和遍历从容器对象中分离出来,使得容器和迭代器可以独立地变化。

2、为什么使用迭代器模式

  1. 分离集合与遍历:迭代器模式将集合对象的遍历行为封装到迭代器中,使得集合与遍历的关注点分离。
  2. 简化集合接口:迭代器提供了一个统一的遍历接口,简化了集合类的接口,使得集合的实现更加简洁。
  3. 支持多种遍历方法:通过不同的迭代器实现,可以支持不同的遍历方法,比如正序、逆序、过滤等。

3、如何使用迭代器模式

设计实现一个集合类来实现迭代器模式

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

// 迭代器接口
interface MyIterator {
    boolean hasNext();
    Object next();
}

// 集合接口
interface MyCollection {
    MyIterator createIterator();
}

// 具体迭代器实现
class MyListIterator implements MyIterator {
    private List<Object> list;
    private int index = 0;

    MyListIterator(List<Object> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        return index < list.size();
    }

    @Override
    public Object next() {
        if (hasNext()) {
            return list.get(index++);
        }
        return null;
    }
}

// 具体集合实现
class MyListCollection implements MyCollection {
    private List<Object> list = new ArrayList<>();

    // 添加元素
    void addElement(Object element) {
        list.add(element);
    }

    // 创建迭代器
    @Override
    public MyIterator createIterator() {
        return new MyListIterator(list);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        MyListCollection collection = new MyListCollection();
        collection.addElement("Element 1");
        collection.addElement("Element 2");
        collection.addElement("Element 3");

        // 使用迭代器遍历集合
        MyIterator iterator = collection.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

4、是否存在缺陷和不足

迭代器模式不适用于所有的集合,主要是集合内部结构不方便直接使用迭代器的场景。

5、如何缓解缺陷和不足

  1. 使用增强的 for 循环:对于一些简单的集合,可以使用增强的 for 循环替代迭代器,代码更加简洁。
  2. 考虑其他遍历方式:如果迭代器不适用于某些集合,可以考虑其他遍历方式,比如通过索引访问元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1323193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024 年 8 个顶级开源 LLM(大语言模型)

如果没有所谓的大型语言模型&#xff08;LLM&#xff09;&#xff0c;当前的生成式人工智能革命就不可能实现。LLM 基于 transformers&#xff08;一种强大的神经架构&#xff09;是用于建模和处理人类语言的 AI 系统。它们之所以被称为“大”&#xff0c;是因为它们有数亿甚至…

Axure的案例演示

增删改查&#xff1a; 在中继器里面展示照片

第三讲GNSS相关时间系统和转换 第四讲观测值的产生和分类 | GNSS(RTK)课程学习笔记day2

说明&#xff1a;以下笔记来自计算机视觉life吴桐老师课程&#xff1a;从零掌握GNSS、RTK定位[链接]&#xff0c;从零掌握RTKLIB[链接]。非原创&#xff01;且笔记仅供自身与大家学习使用&#xff0c;无利益目的。 第三讲 GNSS相关时间系统和转换 GPS卫星的位置在时间过程中是…

SpringCloud源码探析(十二)-基于SpringBoot开发自定义中间件

1.概述 中间件是一种介于操作系统和应用软件之间&#xff0c;为应用软件提供服务功能的软件&#xff0c;按功能划分有消息中间件&#xff08;Kafka、RocketMQ&#xff09;、通信中间件&#xff08;RPC通信中间件&#xff0c;dubbo等&#xff09;&#xff0c;应用服务器等。中间…

等保测评主要保护哪些方面的安全?

等保测评是经公安部认证的具有资质的测评机构&#xff0c;依据国家信息安全等级保护规范规定&#xff0c;受有关单位委托&#xff0c;按照有关管理规范和技术标准&#xff0c;对信息系统安全等级保护状况进行检测评估的活动。那么企业做等保“保”的是什么呢&#xff1f; 等保主…

《空气质量持续改善行动计划》发布,汉威科技助力蓝天保卫战

近日&#xff0c;国务院印发《空气质量持续改善行动计划》&#xff0c;这是继2013年“大气十条”之后的第三个国家层面的保卫蓝天行动计划。 计划要求协同推进降碳、减污、扩绿、增长&#xff0c;以改善空气质量为核心&#xff0c;以减少重污染天气和解决人民群众身边的突出大…

深入理解 HTTP 和 HTTPS:提升你的网站安全性(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Android Studio问题解决:Gradle Download 下载超时 Connect reset

文章目录 一、遇到问题二、解决办法 一、遇到问题 Gradle Download下载超时Sync了很多次&#xff0c;一直失败 二、解决办法 手动通过gradle网站下载 https://gradle.org/releases/可能也会出现超时&#xff0c;最好开个VPN软件会比较快。 下载好的软件&#xff0c;放到本机的…

自定义IDEA代码补全插件

目标&#xff1a; 对于项目中的静态方法&#xff08;主要是各种工具类里的静态方法&#xff09;&#xff0c;可以在输入方法名时直接提示相关的静态方法&#xff0c;选中后自动补全代码&#xff0c;并导入静态类。 设计&#xff1a; 初步构想&#xff0c;用户选择要导入的文…

得物-Golang-记一次线上服务的内存泄露排查

1.出现内存泄漏 1.1 事发现场 在风和日丽的一天&#xff0c;本人正看着需求、敲着代码&#xff0c;展望美好的未来。突然收到一条内存使用率过高的告警。 1.2 证人证词 告警的这个项目&#xff0c;老代码是python的&#xff0c;最近一直在go化。随着go化率不断上升&#xff…

nodejs+vue+微信小程序+python+PHP协同过滤算法的电影推荐系统-计算机毕业设计推荐python

信息数据的处理完全依赖人工进行操作&#xff0c;会耗费大量的人工成本&#xff0c;特别是面对大量的数据信息时&#xff0c;传统人工操作不仅不能对数据的出错率进行保证&#xff0c; 所以电子化信息管理的出现就能缓解以及改变传统人工方式面临的处境&#xff0c;一方面可以确…

管理类联考——数学——真题篇——按题型分类——充分性判断题——蒙猜D

先看目录&#xff0c;除了2018年比较怪&#xff0c;其他最多2个D&#xff08;数学只有两个弟弟&#xff0c;一个大弟&#xff0c;一个小弟&#xff09; 文章目录 2023真题&#xff08;2023-16&#xff09;-D 2022真题&#xff08;2022-21&#xff09;-D-分析选项⇒是否等价⇒是…

pycharm中如何去除波浪线的设置

pycharm中&#xff0c;碰到恼人的红绿波浪线&#xff0c;打开’file-settings’&#xff0c;然后&#xff0c;参照如图设置&#xff0c;去除’effects’选项&#xff1a;

AWS 知识二:AWS同一个VPC下的ubuntu实例通过ldapsearch命令查询目录用户信息

前言&#xff1a; 前提&#xff1a;需要完成我的AWS 知识一创建一个成功运行的目录。 主要两个重要&#xff1a;1.本地windows如何通过SSH的方式连接到Ubuntu实例 2.ldapsearch命令的构成 一 &#xff0c;启动一个新的Ubuntu实例 1.创建一个ubuntu实例 具体创建实例步骤我就不…

深入了解常见的应用层网络协议

目录 1. HTTP协议 1.1. 工作原理 1.2. 应用场景 1.3. 安全性考虑 2. SMTP协议 2.1. 工作原理 2.2. 应用场景 2.3. 安全性考虑 3. FTP协议 3.1. 工作原理 3.2. 应用场景 3.3. 安全性考虑 4. DNS协议 4.1. 工作原理 4.2. 应用场景 4.3. 安全性考虑 5. 安全性考虑…

用23种设计模式打造一个cocos creator的游戏框架----(二十一)组合模式

1、模式标准 模式名称&#xff1a;组合模式 模式分类&#xff1a;结构型 模式意图&#xff1a;将对象组合成树型结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。 结构图&#xff1a; 适用于&#xff1a; 1、想表示对象的部分…

『OPEN3D』1.5.4 动手实现点云八叉树(OctoTree)最近邻

本专栏地址: https://blog.csdn.net/qq_41366026/category_12186023.html?spm=1001.2014.3001.5482 在二维和三维空间中,我们可以采用四叉树(Quad tree)和八叉树(Octree)这两种特定的数据结构来处理空间分割。这些树形结构可以看作是K-d树在不同维度下的扩展。…

C7练习题答案

一、单项选择题(本大题共20小题,每小题2分,共40分。在每小题给出的四个备选项中,选出一个正确的答案,并将所选项前的字母填写在答题纸的相应位置上。) 以下不是 C 语言的特点的是BA. C 简洁,紧凑 B.不能够编制出功能复杂的程序 C. C语言可以直接对硬件进行操作 D. 语言 C 语言…

云原生之深入解析Kubernetes集群发生网络异常时如何排查

一、Pod 网络异常 网络不可达&#xff0c;主要现象为 ping 不通&#xff0c;其可能原因为&#xff1a; 源端和目的端防火墙&#xff08;iptables, selinux&#xff09;限制&#xff1b; 网络路由配置不正确&#xff1b; 源端和目的端的系统负载过高&#xff0c;网络连接数满…

没有数据线,在手机上查看电脑备忘录怎么操作

在工作中&#xff0c;电脑和手机是我最常用的工具。我经常需要在电脑上记录一些重要的工作事项&#xff0c;然后又需要在手机上查看这些记录&#xff0c;以便随时了解工作进展。但是&#xff0c;每次都需要通过数据线来传输数据&#xff0c;实在是太麻烦了。 有一次&#xff0…