责任链模式一般和过滤器模式组合一起使用,即创建一个链条,经过这个链条处理的所有对象和数据分别进行依次加工,每个环节负责处理不同的业务,环节间彼此独立解耦,同时可以复用。这种设计的巧妙之处在于可以链式调用,不同的过滤方式可以灵活的排序和组合。既可以使用单个过滤器进行处理,也可以直接添加一条责任链。
命令模式
寺庙里的和尚除了打水工作之外,还有很多工作要做,所有的工作安排都是按照主持的指令来执行的,比如某日清晨的工作安排如下:
1.一号和尚做早餐;
2.二号和尚扫庭院;
3.三号和尚敲古钟;
结构定义
public class Command implements Serializable { // 做早餐,打扫,敲钟等指令标识 private OrderTypeEnum order; // 正向执行OR逆向回滚 private Integer direction; // 省略get和set方法}// 指令动作执行器,每种指令对应一个实现public interface OrderHandler { /** * 执行逻辑 * * @param callContext * @return */ PipeResult execute(CallContext callContext); /** * 支持的命令类型:做早餐,打扫,敲钟等命令标识 * * @return */ OrderTypeEnum getOrderType();}// 指令类型管理器public interface PipelineCmd { /** * 指令行定义 * * @return */ Command getCommand(); /** * 执行逻辑 * * @param pipeContext * @return */ PipeResult execute(PipeContext pipeContext); /** * 如果可以撤消指令,则此方法应返回true ,否则返回false * * @return */ default boolean isReversible() { return true; }} // 指令执行器管理器 public interface CmdHandler { /** * 业务执行 * * @param callContext * @return */ PipeResult execute(CallContext callContext); /** * 业务回滚(只回滚当前指令) * * @param callContext * @return */ PipeResult rollback(CallContext callContext); /** * 全部回滚 * * @param pipeContext * @return */ PipeResult rollbackAll(PipeContext pipeContext);}
命令实现
public class ZhuChiCmd implements PipelineCmd { private Command command; private transient OrderHandler orderHandler; public StepCmd(Command command, OrderHandler orderHandler) { this.command = command; this.orderHandler= orderHandler; } @Override public PipeResult execute(PipeContext pipeContext) { return orderHandler.execute(new CallContext(command, pipeContext)); } // 省略get和set方法} public class Breakfast implements OrderHandler { /** * 执行逻辑 * * @param callContext * @return */ PipeResult execute(CallContext callContext){ System.out.println("做早餐啦!"); } /** * 支持的指令类型:做早餐,打扫,敲钟等指令标识 * * @return */ OrderTypeEnum getOrderType(){ return OrderTypeEnum.BREAKFAST; }}public class Clean implements OrderHandler { /** * 执行逻辑 * * @param callContext * @return */ PipeResult execute(CallContext callContext){ System.out.println("打扫庭院啦!"); } /** * 支持的指令类型:做早餐,打扫,敲钟等命令标识 * * @return */ OrderTypeEnum getOrderType(){ return OrderTypeEnum.CLEAN; }}public class Ring implements OrderHandler { /** * 执行逻辑 * * @param callContext * @return */ PipeResult execute(CallContext callContext){ System.out.println("敲钟啦!"); } /** * 支持的命令类型:做早餐,打扫,敲钟等指令标识 * * @return */ OrderTypeEnum getOrderType(){ return OrderTypeEnum.Ring; }}public class CmdFactory { private List orderHandlerList; /** * 获取指定指令条件的指令对象 * * @param command * @return */ public PipelineCmd getPipelineCmd(Command command) { for (OrderHandler orderHandler : orderHandlerList) { OrderTypeEnum orderTypeEnum = orderHandler.getOrderType(); if (orderTypeEnum.equals(command.getOrder())) { return new ZhuChiCmd(command, orderHandler); } } throw new RuntimeException("对不起主持:没有多余的和尚来执行新命令了!"); } /** * 获取给定指令的回滚操作指令对象 * * @param command * @return */ public PipelineCmd getRollbackPipelineCmd(Command command) { Command rollbackCommand = getRollbackCommand(command); return getPipelineCmd(rollbackCommand); }}
具体使用
public class CmdHandlerImpl implements CmdHandler { private CmdFactory cmdFactory; @Override public PipeResult execute(CallContext callContext) { PipelineCmd pipelineCmd = cmdFactory.getPipelineCmd(callContext.getCommand()); PipeResult pipeResult = pipelineCmd.execute(callContext.getPipeContext()); return pipeResult; } @Override public PipeResult rollback(CallContext callContext) { Command rollbackCommand = cmdFactory.getRollbackCommand(callContext.getCommand()); if (rollbackCommand == null) { return new PipeResult("不需要回滚"); } PipelineCmd pipelineCmd = cmdFactory.getPipelineCmd(rollbackCommand); if (!pipelineCmd.isReversible()) { return new PipeResult("不支持回滚"); } PipeResult pipeResult = pipelineCmd.execute(callContext.getPipeContext()); return pipeResult; } @Override public PipeResult rollbackAll(PipeContext pipeContext) { // 命令执行备忘录模式对象,这里不再展开 Caretaker caretaker = pipeContext.getCaretaker(); // 拿到上一步执行命令,依次循环回滚 Command command = caretaker.pop(); while (command != null) { PipelineCmd pipelineCmd = cmdFactory.getRollbackPipelineCmd(command); if (pipelineCmd != null) { pipelineCmd.execute(pipeContext); } command = caretaker.pop(); } return new PipeResult(); }}
命令模式将一个请求封装为一个对象,使发出的请求的对象和执行请求的对象分割开。这两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。命令模式可以与备忘录模式组合使用,方便实现Undo和Redo操作。
3.3 实践心得设计原则
具体包含单一职责原则SRP、开闭原则OCP、里氏替换原则LSP、依赖倒置原则DIP、接口隔离原则ISP、最少知识原则LKP等很多种,其核心还是围绕着低耦合,高复用,高内聚,易扩展,易维护展开的。
模式与原则
1.设计原则是指导思想,设计模式是实现手段之一;
2.设计原则在实际开发中并不能做到完全遵守,往往是打破一些原则,遵守一些原则,来实现设计的合理性;(成本,性能)
3.设计模式往往是问题解决方案的骨架,有时候可以当做开发规范和任务拆分执行落地的技术手段;
4.一个设计模式,往往不仅仅采用一种设计原则,而是一些设计原则的整合;
5.设计模式不是一成不变的,可以根据问题场景,输出新的模式;
6.一个复杂场景问题,有时候需要多种设计模式的组合;
7.学设计模式,死记硬背是没用的,要从实践中习得;
8.避免设计过度,使简单的问题复杂化。一定要牢记简洁原则,设计模式是为了使设计简单,而不是更复杂;
四 总结
本文从设计模式与编程语言的关系,设计模式与架构模式的区别,设计原则和设计模式的关系等几个维度进行了分析和解答。关于设计模式应该如何学习和应用的问题,给出了学习意见和实践心得。当然,为了让设计模式更加的直观和立体,也花了大量篇幅在应用实践案例上面,主要是通过场景化的案例,以设计模式的方式给出解决方案,其中部分场景为了方便理解,将问题做了简化处理,但这不影响我们去理解设计模式要解决的问题类型。冰冻三尺非一日之寒,滴水石穿非一日之功,希望本文能够为你带来帮助。