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

news/2024/12/15 5:50:59/

模板方法模式 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.ppmy.cn/news/1275608.html

相关文章

C++使用UDP

C使用UDP 对C使用UDP做了简单封装&#xff0c;可直接运行 头文件udp.h #pragma once #include <Winsock.h> #pragma comment(lib,"WS2_32.lib")#define LOCAL_IP_ADDR INADDR_ANY //当前应用程序接收的IP地址 #define LOCAL_PORT 9527 …

js 字符串功能转换解析

一. 字符串转换 1.1. 对象转字符串stringify var str JSON.stringify(weather);1.2. 字符串转对象 var obj JSON.parse(str);1.3. 数字转字符串toString() var num 2023; var str ; str num.toString();1.4. 字符串转数字parseInt(string) parseInt(123)&#xff0c;…

面试记录一

1.MYSQL查询语句 问&#xff1a; 我有一条sql语句 selet * from user where id in(5,10,8) 我要查询出来的数据要按照我的in里面包含的顺序显示出来 答&#xff1a; SELECT * FROM user WHERE id IN (5,10,8) ORDER BY CASE id WHEN 5 THEN 1 WHEN 10 THEN 2 …

基于CNN+数据增强+残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)+数据集+模型(二)

系列文章目录 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型&#xff08;一&#xff09; 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型&#xf…

springCould中的Eureka-从小白开始【2】

目录 1.什么是Eureka ❤️❤️❤️ 2. 组件❤️❤️❤️ 3.单机Eureka配置❤️❤️❤️ 4.服务8001服务入住eureka ❤️❤️❤️ 5.消费端80入住到eureka ❤️❤️❤️ 6.集群Eureka配置 ❤️❤️❤️ 7.将Client发布到eureka集群上 ❤️❤️❤️ 8.服务端8002集群搭建…

WPF仿网易云搭建笔记(7):HandyControl重构

文章目录 专栏和Gitee仓库前言相关文章 新建项目项目环境项目结构 代码结果结尾 专栏和Gitee仓库 WPF仿网易云 Gitee仓库 WPF仿网易云 CSDN博客专栏 前言 最近我发现Material Design UI的功能比较简单&#xff0c;想实现一些比较简单的功能&#xff0c;比如消息提示&#xff0…

netty-daxin-3(rpc远程调用)

文章目录 nettyRpcObjectEncoder 与 ObjectDecoderjdk动态代理回顾Rpc调用过程简析服务端客户端 nettyRpc ObjectEncoder 与 ObjectDecoder ObjectEncoder继承自MessageToByteEncoder<Serializable>&#xff0c;它内部使用ByteBufOutputStream包装ByteBuf对象&#xff…

【Image】图像处理

计算机视觉 CV Perception 如自动驾驶领域。 只要是从所谓的图像当中去抽取信息的过程&#xff0c;我们都叫做Perception。 视觉检测可以涵盖二维检测&#xff0c;如车辆、人和信号灯的检测。另外&#xff0c;还可以控制三维信息&#xff0c;直接在三维空间中操作数据。 SL…