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

模板方法模式 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.mzph.cn/news/233490.shtml

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

相关文章

iManager服务备份

这里写自定义目录标题 超图微服务云套件大版本升级时&#xff0c;有时候会涉及服务的迁移或重新发布&#xff0c;此时需要对服务进行备份&#xff0c;以免重新发布服务出现漏的&#xff0c;便于核对。本文通过fetch实现了服务的备份&#xff0c;备份成果以数组对象形式存储在tx…

Ubuntu环境下SomeIP/CommonAPI环境搭建详细步骤

环境搭建 1.Boost安装 下载Boost源码 &#xff1a; https://www.boost.org/users/download/ 编译安装 首先安装编译所需依赖 sudo apt-get install build-essential g sudo apt-get install installpython-dev autotools-dev sudo apt-get install installlibicu-dev buil…

搭建知识付费平台?明理信息科技为你提供全程解决方案

明理信息科技saas知识付费平台 在当今数字化时代&#xff0c;知识付费已经成为一种趋势&#xff0c;越来越多的人愿意为有价值的知识付费。然而&#xff0c;公共知识付费平台虽然内容丰富&#xff0c;但难以满足个人或企业个性化的需求和品牌打造。同时&#xff0c;开发和维护…

【容器Docker】Docker学习笔记

1、什么是Docker&#xff1a; Docker 将程序和程序运行所依赖的所有环境都打包到镜像里。“build once, run anywhere”Docker 是容器的一种实现。 Windows 下如何安装Docker: 官方安装教程&#xff1a;Install Docker Desktop on Windows | Docker Docs有两种安装套装&…

使用openMVS库,在VS2022中启用c++17标准编译仍然报错

使用openMVS库&#xff0c;在VS2022中启用c17标准编译仍然报错 现象 项目中引用了某些开源库&#xff08;例如openmvs2.1.0&#xff09;&#xff0c;编译时要求启用编译器对c17的支持。 没问题&#xff01;大家都知道在下图所示的位置调整C语言标准&#xff1a; 但是&#…

sqlite3使用中的问题

1、创建自增使用 integer primary key autoincrement 2、注释使用 – 3、创建表时不能同时创建索引&#xff0c;需要create index 4、删除索引使用drop indx 5、在使用soci更新数据库时&#xff0c;数据没有更新&#xff0c;需要使用statement.execute(true) 6、在使用命令查询…

C++常见面试题-进阶部分50题

问题1&#xff1a; 解释C中的模板元编程是什么。 答案&#xff1a; 模板元编程是一种利用C模板来执行编译时计算的技术。它允许程序在编译期间进行复杂的计算&#xff0c;而非运行时。 问题2&#xff1a; C17中的结构化绑定是什么&#xff1f; 答案&#xff1a; 结构化绑定是…

智能优化算法应用:基于类电磁机制算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于类电磁机制算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于类电磁机制算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.类电磁机制算法4.实验参数设定5.算法…

rpc和消息队列区别

RPC 和消息队列都是分布式微服务系统中重要的组件之一&#xff0c;下面我们来简单对比一下两者&#xff1a; 从用途来看&#xff1a;RPC 主要用来解决两个服务的远程通信问题&#xff0c;不需要了解底层网络的通信机制。通过 RPC可以帮助我们调用远程计算机上某个服务的方法&a…

Unity CG内置文件

文档 内置文件 内置文件中的函数 常用宏 变量 CG内置文件位置和作用 位置 Unity安装目录 Editor/Data/CGIncludes中后缀为cginc的文件 作用 类似CG内置函数&#xff0c;提供常用的函数、结构体、变量等&#xff0c;提高开发效率 使用 CG模块中使用 #include “内置文件…

ArcGIS Pro中去除黑边方法汇总

在有些时候&#xff08;比如镶嵌栅格后&#xff09;&#xff0c;我们获取到的影像数据可能会有黑边&#xff0c;这里为大家汇总一下在ArcGIS Pro中去除黑边的方法&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用的数据是从水经微图中下载的影像数据&#xff0c;除了…

vmware离线安装docker-compose

vmware离线安装docker-compose 最近安装docker-compose&#xff0c;发现git取拉取&#xff0c;不是拒绝连接就是报443错误&#xff0c;或者其他错误 最后发现用包直接传上去好用&#xff0c;不用git拉取了 离线安装docker-compose 本文章给的docker-compose离线包&#xff0c;…

C语言学习第二十四天(预处理)

1、预处理符号 C语言设置了一些可以直接使用的预处理符号 __FILE__//进行编译的源文件 __LINE__//文件当前的行号 __DATE__//文件被编译的日期 __TIME__//文件被编译的时间 __STOC__//如果编译器遵循ANSI C 其值是1&#xff0c;否则未定义 一个例子&#xff1a; printf(&…

JNDI注入Log4jFastJson白盒审计不回显处理

目录 0x00 前言 0x01 Maven 仓库及配置 0x02 JNDI 注入简介 0x03 Java-第三方组件-Log4J&JNDI 0x04 Java-第三方组件-FastJson&反射 0x05 白盒审计 - FastJson 0x06 白盒审计 - Log4j 0x07 不回显的处理方法 0x00 前言 希望和各位大佬一起学习&#xff0c;如果…

多线程面试题

文章目录 1. 如何停止正在运行的线程2. 请你谈谈JMM&#xff08;java内存模型&#xff09;3. AQS4. ReentrantLock实现原理5. 死锁怎么检测 1. 如何停止正在运行的线程 设置一个共享变量作为线程退出的标记&#xff0c;当这个标记不满足时while循环&#xff0c;线程一直运行&a…

uniapp图片上传说明

目录 1.文件上传组件 2.单文件上传 3.多文件上传 4.注意点 1.文件上传组件 前端上传组件使用uni-file-picker&#xff0c;可以自行进行下载使用。默认上传到绑定的服务空间&#xff0c;配置属性auto-upload为false关闭自动上传&#xff0c;可以限定上传的是图片还是文件&am…

Databend 开源周报第 124 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 新增对 Delta 和…

使用Python编写简单网络爬虫实例:爬取图片

&#x1f34e;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 ​编辑 简介 步骤 1. 安装依赖库 2. 创建目录 3. 发送HTTP请求并解析页面 4. 查找图片标签并下载图片 注意事项 结语 我的其他博客 简介 网络爬虫是一种…

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

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

【js文件】谷歌地图 markerclusterer.js

谷歌地图,点聚合,所使用的js function MarkerClusterer(map, opt_markers, opt_options) {this.extend(MarkerClusterer, google.maps.OverlayView);this.map_ map;/*** type {Array.<google.maps.Marker>}* private*/this.markers_ [];/*** type {Array.<Cluster&…