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

模板方法模式 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 {@Overridevoid addCondiments() {System.out.println("Adding lemon");}
}// 具体子类,制作咖啡
class CoffeeTemplateImpl extends CoffeeTemplate {@Overridevoid 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 {@Overridevoid addCondiments() {System.out.println("Adding lemon");}// 通过重写钩子方法,决定是否添加调料@Overrideboolean customerWantsCondiments() {// 用户不想要调料return false;}
}// 具体子类,制作咖啡
class CoffeeTemplateImpl extends CoffeeTemplate {@Overridevoid 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 {@Overridepublic void addCondiments() {System.out.println("Adding lemon");}
}// 具体的调料策略,添加糖和牛奶
class SugarAndMilkCondiments implements CondimentsStrategy {@Overridepublic 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;}@Overridepublic boolean hasNext() {return index < list.size();}@Overridepublic 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);}// 创建迭代器@Overridepublic 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.rhkb.cn/news/222002.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode配置node.js调试环境

node.js基于VSCode的开发环境的搭建非常简单。 说明&#xff1a;本文的前置条件是已安装好node.js(具体安装不再赘述&#xff0c;如有需要可评论区留言)。 阅读本文可掌握&#xff1a; 方便地进行js单步调试&#xff1b;方便地查看内置的对象或属性&#xff1b; 安装插件 C…

RouterSrv-DHCP

2023年全国网络系统管理赛项真题 模块B-Windows解析 题目 安装和配置DHCP relay服务,为办公区域网络提供地址上网。DHCP服务器位于AppSrv服务器上。拆分DHCP服务器上的作用域,拆分的百分比为7:3。InsideCli优先从RouterSrv获取地址。配置步骤 安装和配置DHCP relay服务,为办…

AIGC:阿里开源大模型通义千问部署与实战

1 引言 通义千问-7B&#xff08;Qwen-7B&#xff09;是阿里云研发的通义千问大模型系列的70亿参数规模的模型。Qwen-7B是基于Transformer的大语言模型, 在超大规模的预训练数据上进行训练得到。预训练数据类型多样&#xff0c;覆盖广泛&#xff0c;包括大量网络文本、专业书籍…

云原生消息流系统 Apache Pulsar 在腾讯云的大规模生产实践

导语 由 InfoQ 主办的 Qcon 全球软件开发者大会北京站上周已精彩落幕&#xff0c;腾讯云中间件团队的冉小龙参与了《云原生机构设计与音视频技术应用》专题&#xff0c;带来了以《云原生消息流系统 Apache Pulsar 在腾讯云的大规模生产实践》为主题的精彩演讲&#xff0c;在本…

Linux shell编程学习笔记37:readarray命令和mapfile命令

目录 0 前言1 readarray命令的格式和功能 1.1 命令格式1.2 命令功能1.3 注意事项2 命令应用实例 2.1 从标准输入读取数据时不指定数组名&#xff0c;则数据会保存到MAPFILE数组中2.2 从标准输入读取数据并存储到指定的数组2.3 使用 -O 选项指定起始下标2.4 用-n指定有效行数…

21.Servlet 技术

JavaWeb应用的概念 在Sun的Java Servlet规范中&#xff0c;对Java Web应用作了这样定义&#xff1a;“Java Web应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在各种供应商提供的实现Servlet规范的 Servlet容器 中运行。” Java Web应用中可以包含如下…

人工智能的发展之路:时间节点、问题与解决办法的全景解析

导言 人工智能的发展历程充满了里程碑式的事件&#xff0c;从早期的概念到今天的广泛应用&#xff0c;每个时间节点都伴随着独特的挑战和创新。本文将详细描述每个关键时间节点的事件&#xff0c;探讨存在的问题、解决办法&#xff0c;以及不同阶段之间的联系。 1. 195…

重温经典struts1之自定义转换器及注册的两种方式(Servlet,PlugIn)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 Struts的ActionServlet接收用户在浏览器发送的请求&#xff0c;并将用户输入的数据&#xff0c;按照FormBean中定义的数据类型&#xff0c;赋值给FormBean中每个变量&a…

Databend 源码阅读: Meta-service 数据结构

作者&#xff1a;张炎泼&#xff08;XP&#xff09; Databend Labs 成员&#xff0c;Databend 分布式研发负责人 drmingdrmer (张炎泼) GitHub 引言 Databend 是一款开源的云原生数据库&#xff0c;采用 Rust 语言开发&#xff0c;专为云原生数据仓库的需求而设计。 面向云架…

利用prometheus+grafana进行Linux主机监控

文章目录 一.架构说明与资源准备二.部署prometheus1.上传软件包2.解压软件包并移动到指定位置3.修改配置文件4.编写启动脚本5.启动prometheus服务 三.部署node-exporter1.上传和解压软件包2.设置systemctl启动3.启动服务 四.部署grafana1.安装和启动grafana2.设置prometheus数据…

第二节TypeScript 基础语法

1、typescript程序由以下几个部分组成&#xff1a; 模块函数变量语句和表达式注释 2、开始第一个typescript程序 创建一个typescript程序&#xff0c;使之输出“hello typescript”&#xff1a; 代码&#xff1a; var message:string "hello typescript" cons…

美颜SDK技术对比,深入了解视频美颜SDK的工作机制

如何在实时视频中呈现更加自然、美丽的画面&#xff0c;而这正是美颜SDK技术发挥作用的领域之一。本文将对几种主流视频美颜SDK进行深入比较&#xff0c;以揭示它们的工作机制及各自的优劣之处。 随着科技的不断进步&#xff0c;美颜技术已经从简单的图片处理发展到了视频领域…

Flink系列之:背压下的检查点

Flink系列之&#xff1a;背压下的检查点 一、Checkpointing under backpressure二、缓冲区 Debloating三、非对齐 Checkpoints四、对齐 Checkpoint 的超时五、限制六、故障排除 一、Checkpointing under backpressure 通常情况下&#xff0c;对齐 Checkpoint 的时长主要受 Che…

【运维面试100问】(十一)淡淡I/O过程

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

关于“Python”的核心知识点整理大全32

目录 12.6.4 调整飞船的速度 settings.py ship.py alien_invasion.py 12.6.5 限制飞船的活动范围 ship.py 12.6.6 重构 check_events() game_functions.py 12.7 简单回顾 12.7.1 alien_invasion.py 12.7.2 settings.py 12.7.3 game_functions.py 12.7.4 ship.py …

本地MinIO存储服务如何创建Buckets并实现公网访问上传文件

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 前言 MinIO是一款高性能、分布式的对象存储系统&#xff0c;它可以100%的运行在标准硬件上&#xff0c;即X86等…

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

老老规矩&#xff0c;看目录&#xff0c;平均每年2E&#xff0c;跟2D一样&#xff0c;D是全对&#xff0c;E是全错&#xff0c;侧面也看出10道题&#xff0c;大概是3A/B&#xff0c;3C&#xff0c;2D&#xff0c;2E&#xff0c;其实还是蛮平均的。但E为1道的情况居多。 第20题…

Linux目录和文件管理

一.Linux目录结构 Linux操作系统在定位文件或目录位置时&#xff0c;使用斜杠“ / ”进行分割&#xff08;区别于Windows操作系统中的反斜杠“ \ ”&#xff09;。整个树形目录结构中&#xff0c;使用独立的一个" / "表示根目录&#xff0c;根目录是Linux操作系统文…

vue2 组件传递数据

向子组件传递数据通过Props 1.创建子组件 详细步骤&#xff1a; 1.在components创建子组件 2.等父组件接受到参数后通过Props来接受父组件传递过来的数据 <template><div id"app"><h2>title:{{ title }}</h2><p>tips:{{ tips }}<…

androidStudio版本下载链接记录

androidStudio 最新官网版本&#xff1a; 下载 Android Studio 和应用工具 - Android 开发者 | Android DevelopersAndroid Studio 提供了一些应用构建器以及一个已针对 Android 应用进行优化的集成式开发环境 (IDE)。立即下载 Android Studio。https://developer.android.g…