【再探】设计模式—职责链模式、命令模式及迭代器模式

2024-05-27 12:36

本文主要是介绍【再探】设计模式—职责链模式、命令模式及迭代器模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 行为型设计模式研究系统在运行时对象之间的交互,进一步明确对象的职责。有职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式及访问模式共11种。

1 职责链模式

需求:1) 请求能被多个处理器处理,对处理顺序有要求。2) 请求与处理器解耦,具体被哪个处理器处理未知,可动态决定其处理器。

1.1 职责链模式介绍

通过建立一条链来组织请求的处理者。请求将沿着链进行传递,请求发送者无需知道请求在何时、何处及如何被处理,实现了请求发送者与处理者的解耦。

图 职责链模式UML

public class ChainOfResponsibility {public static void main(String[] args) {RequestHandler requestHandler = generateChain();List<CustomRequest> requestList = generateRequest();for (CustomRequest request : requestList) {try {requestHandler.handle(request);} catch (Exception e) {System.err.println(e.getMessage());}}}private static RequestHandler generateChain() {RequestHandler handler = new SubjectHandler();RequestHandler usernameHandler = new UserNameHandler(handler);return new IpRequestHandler(usernameHandler);}private static List<CustomRequest> generateRequest() {List<CustomRequest> list = new ArrayList<>();list.add(new CustomRequest("localhost", "user"));list.add(new CustomRequest("172.34.43.32", "admin"));list.add(new CustomRequest("172.34.24.24", "user"));return list;}private static class CustomRequest {String ip;String username;public CustomRequest(String ip, String username) {this.ip = ip;this.username = username;}@Overridepublic String toString() {return "CustomRequest{" +"ip='" + ip + '\'' +", username='" + username + '\'' +'}';}}private static abstract class RequestHandler {protected final RequestHandler handler;public RequestHandler(RequestHandler handler) {this.handler = handler;}abstract void handle(CustomRequest request);}private static class IpRequestHandler extends RequestHandler{private static final String[] BLACK_IPS = {"localhost","127.0.0.1"};public IpRequestHandler(RequestHandler handler) {super(handler);}@Overridevoid handle(CustomRequest request) {if (request.ip == null) {throw new RuntimeException("请求IP 不合法");} else {for (String str : BLACK_IPS) {if (request.ip.contains(str)) throw new RuntimeException("请求IP 不合法");}}handler.handle(request);}}private static class UserNameHandler extends RequestHandler {public UserNameHandler(RequestHandler handler) {super(handler);}@Overridevoid handle(CustomRequest request) {if (request.username == null) {throw new RuntimeException("用户名不能为空");} else {if (request.username.contains("admin")) throw new RuntimeException("用户名不合法");}handler.handle(request);}}private static class SubjectHandler extends RequestHandler {public SubjectHandler() {super(null);}@Overridevoid handle(CustomRequest request) {System.out.println("请求到达目标处理器:" + request);}}}

纯职责链模式

要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,而且一个请求必须被某一个处理者对象所处理。

不纯职责链模式

允许一个具体处理者部分被处理好再向下传递,或者一个具体处理者处理完某请求后,后继处理者可以继续处理改请求。一个请求最终可以不被处理。

图 职责链模式的两种类型

1.2 优缺点

优点:

  1. 将请求发送者与接收者解耦,请求发送者无需知道请求会被哪个处理器处理。
  2. 当系统需要增加一个新的处理者时,无需修改原有系统代码,符合开闭原则。

缺点:

  1. 不能保证请求一定会被处理。如果职责链没有被正确配置,则请求可能得不到处理。
  2. 如果建链不当,则可能会造成循环调用。
  3. 如果职责链较长,系统性能将受到一定影响,代码调试也不方便。

2 命令模式

需求:1)将命令发送者与命令接收者解耦,命令发送者不必关系接收者的接口、命令何时被处理等。2)能对命令发送者发出的命令进行记录、撤销等。3)发送者能发出一系列命令,这些命令能按某种顺序被处理。

2.1 命令模式介绍

引入一个命令类,来降低发送者与接收者的耦合度。将一个命令封装成一个命令对象,发送者只需指定一个命令对象,再通过命令对象来调用接收者的处理方法。

图 命令模式UML

public class CommandPattern {public static void main(String[] args) { // 进入餐馆String[] food_menu = {"麻婆豆腐","红烧茄子","莴笋炒肉","辣子鸡丁","香干炒肉","黄焖鸡"};Cook[] cooks = new Cook[4];for (int i = 0; i < cooks.length; i++) { // 招募厨子cooks[i] = new Cook();}for (int i = 0; i < 10; i++) { // 来了客户点单Customer order = new Customer(i);CookingCommand command = new CookingCommand(cooks);order.placeOrder(command,food_menu);}}private static class Customer {private final int id;public Customer(int id) {this.id = id;}void placeOrder(Command command, String[] foodNames) {Random random = new Random();int num = random.nextInt(foodNames.length) + 1;Set<String> foods = new HashSet<>();while (num > 0) {String foodName = foodNames[random.nextInt(foodNames.length)];if (foods.add(foodName)) num--;}command.makeOrder(foods,id);}}private interface Command {void makeOrder(Collection<String> foodList,int id);}private static class CookingCommand implements Command {private final Cook[] cookList;public CookingCommand(Cook[] cookList) {this.cookList = cookList;}@Overridepublic void makeOrder(Collection<String> foodList,int id) {System.out.println("客户:" + id + ",下单:" + foodList);new Thread(() -> {Date date = new Date();List<String> finished = new ArrayList<>();for (String food : foodList) {boolean cooking = true;int pos = 0;while (cooking) {Cook cook = cookList[pos];try {String finishedFood = cook.cooking(food);finished.add(finishedFood);cooking = false;} catch (Exception e) {pos = (pos + 1) % cookList.length;}}}Date finishedDate = new Date();long distance = (finishedDate.getTime() - date.getTime()) / 1000 ;System.out.println("订单:" + id + "完成,耗时:" + distance + "秒," + finished);}).start();}}private static class Cook {private Boolean isBusy = false;private String cooking(String foodName) throws Exception {if (isBusy) {throw new Exception("没空!");}isBusy = true;System.out.println(foodName + "制作中...");synchronized (this) {Thread.sleep(2000);}isBusy = false;return "f-" + foodName;}}}

2.1.1 命令队列模式

当一个请求发送者发送一个请求时,不止一个请求接收者产生响应,这些请求接收者将逐个执行业务方法,完成对请求的处理。

图 命令队列模式 UML

public class CommandQueuePattern {public static void main(String[] args) {Student student = new Student();Teacher teacher = new Teacher();Command teacherCommand = new TeacherCommand(teacher);Command studentCommand = new StudentCommand(student);CommandQueue commandQueue = new CommandQueue();commandQueue.addCommand(teacherCommand);commandQueue.addCommand(studentCommand);School school = new School();school.setCommandQueue(commandQueue);school.releaseTestNote("3周以后进行考试");}private static class School {private CommandQueue commandQueue;public void setCommandQueue(CommandQueue commandQueue) {this.commandQueue = commandQueue;}public void releaseTestNote(String content) {if (commandQueue != null) commandQueue.execute(content);}}private static class CommandQueue{private final List<Command> commandList = new ArrayList<>();public void addCommand(Command command) {commandList.add(command);}public void clearCommand() {commandList.clear();}public void execute(String content) {for (Command command : commandList) command.execute(content);}}private static abstract class Command {void execute(String content) {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:sss");System.out.println("收到通知:" + content + "," + dateFormat.format(new Date()));invoke(content);}abstract void invoke(String content);}private static class TeacherCommand extends Command {private final Teacher teacher;public TeacherCommand(Teacher teacher) {this.teacher = teacher;}@Overridevoid invoke(String content) {if (teacher != null) teacher.developPlan();}}private static class StudentCommand extends Command {private final Student student;public StudentCommand(Student student) {this.student = student;}@Overridevoid invoke(String content) {if (student != null) student.review();}}private static class Teacher {public void developPlan() {System.out.println("老师开始制定复习计划");}}private static class Student {public void review() {System.out.println("学生开始复习");}}}

2.2 优缺点

优点:

  1. 将请求调用者与请求接收者解耦,使得调用者不必关心接收者的接口、请求何时被处理等。
  2. 将请求封装成一个对象,可以对这请求进行处理。例如记录日志。
  3. 增加新的命令很容易,无须修改原有系统代码结构,甚至客户端代码,符合开闭原则。
  4. 可以比较容易设计成一个命令队列。

缺点:

  1. 会导致系统有过多的具体命令类,同时可能会降低系统性能。

3 迭代器模式

需求:1)将聚合对象存储职责与遍历职责分离开。2)为一个聚合对象提供多种遍历方式。

3.1 迭代器模式介绍

提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示。

图 迭代器模式 UML

public class CustomList<T> {public static void main(String[] args) {CustomList<Integer> list = new CustomList<>();for (int i = 0; i < 21; i++) list.addItem(i);Iterator<?> iterate = list.createIterate();while (iterate.hasNext()) System.out.println(iterate.next());}public Iterator<T> createIterate() {return new CustomIterator();}public interface Iterator<E> {E first();E next();boolean hasNext();E currentItem();}private class CustomIterator implements Iterator<T> {private int pos = 0;@SuppressWarnings("unchecked")@Overridepublic T first() {if (currentPos <= 0) {throw new RuntimeException("访问超出界限");}return (T)items[0];}@SuppressWarnings("unchecked")@Overridepublic T next() {if (hasNext()) {return (T)items[pos++];}return null;}@Overridepublic boolean hasNext() {return pos < currentPos;}@SuppressWarnings("unchecked")@Overridepublic T currentItem() {if (pos == 0) return first();return (T)items[pos-1];}}private static final int INIT_LENGTH = 20;Object[] items;private int currentPos = 0;public CustomList() {this.items = new Object[INIT_LENGTH];}public void addItem(T item) {checkArrayLength();items[currentPos++] = item;}@SuppressWarnings("unchecked")public T getItem(int pos) {if (pos >= currentPos) {throw new RuntimeException("访问超出界限");}return (T)items[pos];}private void checkArrayLength() {if (currentPos == items.length) {items = Arrays.copyOf(items,items.length * 2);}}}

3.2 优缺点

优点:

  1. 支持以不同方式遍历一个聚合对象。
  2. 简化聚合类的职责,将聚合对象的访问和数据的存储分离,使得访问聚合对象无须了解其内部实现细节。

缺点:

  1. 增加了类的个数,设计难度较大。

这篇关于【再探】设计模式—职责链模式、命令模式及迭代器模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007490

相关文章

如何开启和关闭3GB模式

https://jingyan.baidu.com/article/4d58d5414dfc2f9dd4e9c082.html

十五.各设计模式总结与对比

1.各设计模式总结与对比 1.1.课程目标 1、 简要分析GoF 23种设计模式和设计原则,做整体认知。 2、 剖析Spirng的编程思想,启发思维,为之后深入学习Spring做铺垫。 3、 了解各设计模式之间的关联,解决设计模式混淆的问题。 1.2.内容定位 1、 掌握设计模式的"道" ,而不只是"术" 2、 道可道非常道,滴水石穿非一日之功,做好长期修炼的准备。 3、 不要为了

十四、观察者模式与访问者模式详解

21.观察者模式 21.1.课程目标 1、 掌握观察者模式和访问者模式的应用场景。 2、 掌握观察者模式在具体业务场景中的应用。 3、 了解访问者模式的双分派。 4、 观察者模式和访问者模式的优、缺点。 21.2.内容定位 1、 有 Swing开发经验的人群更容易理解观察者模式。 2、 访问者模式被称为最复杂的设计模式。 21.3.观察者模式 观 察 者 模 式 ( Obser

Linux 下的Vim命令宝贝

vim 命令详解(转自:https://www.cnblogs.com/usergaojie/p/4583796.html) vi: Visual Interface 可视化接口 vim: VI iMproved VI增强版 全屏编辑器,模式化编辑器 vim模式: 编辑模式(命令模式)输入模式末行模式 模式转换: 编辑-->输入: i: 在当前光标所在字符的前面,转为输入模式

Linux中拷贝 cp命令中拷贝所有的写法详解

This text from: http://www.jb51.net/article/101641.htm 一、预备  cp就是拷贝,最简单的使用方式就是: cp oldfile newfile 但这样只能拷贝文件,不能拷贝目录,所以通常用: cp -r old/ new/ 那就会把old目录整个拷贝到new目录下。注意,不是把old目录里面的文件拷贝到new目录,

从《深入设计模式》一书中学到的编程智慧

软件设计原则   优秀设计的特征   在开始学习实际的模式前,让我们来看看软件架构的设计过程,了解一下需要达成目标与需要尽量避免的陷阱。 代码复用 无论是开发何种软件产品,成本和时间都最重要的两个维度。较短的开发时间意味着可比竞争对手更早进入市场; 较低的开发成本意味着能够留出更多营销资金,因此能更广泛地覆盖潜在客户。 代码复用是减少开发成本时最常用的方式之一。其意图

Java的简易编译命令

生成jar包 编译生成.class 文件 编译.class文件的命令,其中的参数是输出,原文件路径 javac -sourcepath class.class MyClass.java 如果有包名的需要创建对应包的文件夹,建文件移动对应的包名下在开始包下创建meta-inf文件夹在meta-inf文件下创建manifest.mf文件 生成可运行的jar包 解压 生成了jar包后,进

Builder模式的实现

概念 在创建复杂对象时,将创建该对象的工作交给一个建造者,这个建造者就是一个Builder。在日常的开发中,常常看到,如下这些代码: AlertDialog的实现 AlertDialog.Builder builder = new AlertDialog.Builder(context);builder.setMessage("你好建造者");builder.setTitle

[分布式网络通讯框架]----ZooKeeper下载以及Linux环境下安装与单机模式部署(附带每一步截图)

首先进入apache官网 点击中间的see all Projects->Project List菜单项进入页面 找到zookeeper,进入 在Zookeeper主页的顶部点击菜单Project->Releases,进入Zookeeper发布版本信息页面,如下图: 找到需要下载的版本 进行下载既可,这里我已经下载过3.4.10,所以以下使用3.4.10进行演示其他的步骤。