设计模式理解(一)
十一、命令模式
命令模式是一种行为型模式,将请求以命令的形式包裹在对象里,传递给调用对象,调用对象寻找匹配的命令对象。
计算机科学领域的任何问题都可以加一个间接的中间层来解决。所以将请求者和接受者解耦就可加一层命令层。
主要角色:
抽象命令(Command):命令有通用的特性,将命令抽象成一个类,不同的命令做不同的具体实现
具体命令类(ConcreteCommand):实现抽象命令,做具体的实现。
接受者(Receiver):真正执行命令的对象。
请求者/调用者(Invoker):请求的封装发送者,它通过命令对象来执行请求,不会直接操作接收者,直接关联命令对象,间接调用到接受者的相关操作。
客户端:一般在客户端中创建调用者对象,具体的命令类去执行命令。
// 开空调 // Receiver 真正的操作对象--空调 public class AirConditionReceiver{ public void turnOn(){ System.out.println("开空调"); } public void turnOff(){ System.out.println("关空调"); } } // Command 抽象命令类 public interface Command{ void execute(); } // ConcreteCommand 具体命令类--开命令、关命令 public class TurnOnCommand implements Command{ private AirConditionerReceiver airReceiver; public TurnOnCommand(AirConditionerReceiver airReceiver){ // 默认操作 super(); this.airReceiver = airReceiver; } @Override public void execute(){ airReceiver.turnOn(); } } public class TurnOffCommand implements Command{ private AirConditionerReceiver airReceiver; public TurnOffCommand(AirConditionerReceiver airReceiver){ // 默认操作 super(); this.airReceiver = airReceiver; } @Override public void execute(){ airReceiver.turnOff(); } } // Invoker 调用者/请求者(小爱): public class Invoker{ private Command command; public Invoker(Command command){ this.command = command; } public void action(){ System.out.print("小爱来了,很高兴为您服务==>"); command.execute(); } } // 测试代码 public static void main(String[] args){ Command command = new TurnOnCommand(new AirConditionReceiver); Invoker turnOn = new Invoker(command); turnOn.cation(); // 小爱来了,很高兴为您服务==>开空调 Command command = new TurnOffCommand(new AirConditionReceiver); Invoker turnOff = new Invoker(command); turnOff.cation(); // 小爱来了,很高兴为您服务==>关空调 }
注:缺点是命令过多时,类数量爆炸;优点很明显请求者与接受者解耦
拓展:
如果是多条命令,可以在内部维护一个列表(多个命令对象),添加之后依次执行。
因为执行日志的存在,需要将对象序列化保存起来(磁盘上),维护好执行的状态,在系统故障后,还能从断开的地方继续执行。
如果需要一个撤销(回滚操作),需要在抽象类中加一个undo(),此处中间过程需要维护一个状态(类似数据库的事务回滚)
十二、责任链模式
责任链是一种行为设计模式,允许将请求沿着处理链进行传递处理。责任链模式将一系列处理责任节点视为一个整体,业务请求者不用关心内部业务逻辑与流程。当一个业务需要一系列业务对象去处理时,可将这些业务对象串联作为一条业务责任链,最终实现请求者与响应者的解耦。
主要角色:
Handler:抽象的处理者,定义一个处理请求的接口。
ConcreteHandler:具体的处理者,处理自己负责的请求,可以继续访问其下一个处理者,如果可以处理当前请求则处理,否则就交予下一个处理者,形成一条链。
Request:请求。
例:组装高达,并装好放入透明盒子,最后放到展柜
// Handler 抽象处理者 public interface Handler{ // 设置下一个处理者 Handler setNext(Handler handler); // 业务处理 void process(Request request); } // 抽象-模板方法,抽象子链中的共同方法 public abstract class AbstractHandler implements Handler{ private Handler handler; @Override public void process(Request request){ // 模板方法定义子类的处理 if(!doprocess(request) && this.handler != null){ handler.procee(request); } } @Override public Handler nextHandler(Handler handler){ this.handler = handler; return hanler; } abstract boolean doProcess(Request request); } // 具体实现--拼接 public class AssemblyHandler extends AbstractHandler{ @Override boolean doprocess(Request request){ if(Objects.equals(request.getStatus(),Constants.UNASSEMBLY.getcode())){ //业务处理,拼接模块 assembly(); return true; } return false; } } // 具体实现--装盒 public class BoxingHandler extends AbstractHandler{ @Override boolean doprocess(Request request){ if(Objects.equals(request.getStatus(),Constants.UNBOXING.getcode())){ //业务处理,拼接模块 boxing(); return true; } return false; } } // 具体实现--放入展柜 public class ExhibitHandler extends AbstractHandler{ @Override boolean doprocess(Request request){ if(Objects.equals(request.getStatus(),Constants.UNEXHIBIT.getcode())){ //业务处理,拼接模块 Exhibit(); return true; } return false; } } // 管理器 public class HandlerManage{ public static Handler handler; static{ Handler assemblyHandler = new AssemblyHandler(); Handler boxingHandler = new BoxingHandler(); Handler exhibitHandler = new ExhibitHandler(); // 设置处理链 assemblyHandler.nextHandler(boxingHandler); boxingHandler.nextHandler(exhibitHandler); handler = assemblyHandler; } } // 测试代码 public static void main(String[] args){ Request request = new BlockRequest(Constants.UNEXHIBIT.getcode()); HandlerManage.handler.process(request); }
小结:
1、通过将一系列的处理封装好,请求不用关心整个处理过程。
2、封装好的意味着,不易变更处理。
3、将JavaWeb的Filter的责任链思想借来用用,重点是读书人的借;维护一个集合(处理者的集合),将处理者使用自定义注解按序配置,再将设置下一个处理者的代码改为遍历集合依次处理,达到可配置的责任链条。
十三、备忘录模式
备忘录模式是一种行为型模式,目标是在不破坏封装的前提下,捕获一个对象的内部状态,在该对象之外保存这个状态,用于将对象恢复到之前保存的状态。
分为两部分理解:一是存储副本,便于后续恢复;二是要不违背封装原则的前提下进行对象的备份和恢复。
主要角色:
Originator(发起人):负责创建一个备忘录,记录当前时刻自身的内部状态,并可以使用备份恢复内部状态。
Mementor(备忘录):负责存储发起人的内部状态,通常包含一个或者多个属性,用于表示发起人的状态。
Caretaker(负责人):负责保存备忘录,但不对备忘录的内容进行操作或检查。
适用场景:
需要保存一个对象的当前状态以便后续可恢复,例如:撤销、恢复、保存游戏进度。
实现可回滚的事务操作,也很适用。
// Memento--备忘录 public Class Memento{ private String state; public Memento(String state){ this.state = state; } public String getState(){ return this.state; } public void setState(String state){ this.state = state; } } // Originator--发起人 public class Originator { // 内部状态 private String state; public String getState(){ return this.state; } public void setState(String state){ this.state = state; } // 创建一个备忘录 public Memento createMemento(){ return new Memento(this.state); } // 从备忘录恢复 public void restoreMemento(Memento memento){ this.setState(memento.getState()); } } // Caretaker--负责人 public class Caretaker{ // 备忘录对象 private Memento memento; public Memento getMemento(){ return this.memento; } public void storeMemento(Memento memento){ this.memento = memento; } } public static void main(String[] args){ // 发起人 Originator originator = new Originator(); originator.setState("1"); System.out.println(originator.getState()); // 1 // 负责人 Caretaker caretaker = new Caretaker(); caretaker.storeMemento(originator.createMemento()); origiantor.setState("2"); System.out.println(originator.getState()); // 2 // 管理发起人的备忘录 caretaker.storeMemento(originator.createMemento()); originator.setState("3"); System.out.println(originator.getState()); // 3 // 回滚 originator.restoreMemento(caretaker.getMemento()); System.out.println(originator.getState()); // 2 }
小结:
备忘录模式:防丢失、撤销操作、恢复操作。
针对大对象:不同业务场景进行不同的处理,如:只备份必要的恢复信息、结合新数据恢复、全量备份与增量备份结合、低频全量备份、高频增量备份。
十四、观察者模式
观察者模式是一种对象行为型模式,又称为发布-订阅模式、模型-视图模式,符合依赖倒置原则。
观察者模式:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
示例:请假批假流程,一天只需要经理签字,三天需要主管签字,五天需要总经理,7天需要hr。
// 观察者的顶层接口 public interface observerInterface<T> { // 注册监听者 public void registerListener(T t); // 移除监听者 public void removeListener(T t); // 通知监听者 public void notifyListener(DataEvent t); } // Listener顶级接口,为了抽象Listener public interface MyListener{ void onEvent(DataEvent event); } // Event抽象事件接口 public abstract class DataEvent { private String msg; } // 观察者(同步) @Component public class LoopObserverImpl implements ObserverInterface<MyListener>{ // 监听者的注册列表 private List<Listener> listenerList = new ArrayList<>(); @Override public void registerListener(Mylistener listener){ listenerList.add(listener); } @Override public void removeListener(Mylistener listener){ listenerList.remove(listener); } @Override public void notifyListener(DataEvent event){ for(Mylistener myListener : listenerList){ myListener.onEvent(event); } } } // 请假事件--事件的实现类 public class VacationDataEvent extends DataEvent{ private Integer days; } // 监听者的实现类--经理 @Component public class ManageListener implements Mylistener{ @Override public void onEvent(DataEvent dataEvent){ if(dataEvent instanceof VacationDataEvent){ if(dataEvent.days < 1){ throw new IllegeException("瞎搞,扣钱"); }if else(dataEvent.days < 3){ System.out.println("同意"); }else{ System.out.println("等待主管同意"); } } } } // 监听者的实现类--主管 @Component public class SupervisorListener implements Mylistener{ @Override public void onEvent(DataEvent dataEvent){ if(dataEvent instanceof VacationDataEvent){ if(dataEvent.days < 3){ return; }if else(dataEvent.days < 5){ System.out.println("同意"); }else{ System.out.println("等待总经理同意"); } } } } // 监听者的实现类--总经理 @Component public class GeneralListener implements Mylistener{ @Override public void onEvent(DataEvent dataEvent){ if(dataEvent instanceof VacationDataEvent){ if(dataEvent.days < 5){ return; }if else(dataEvent.days < 7){ System.out.println("同意"); }else{ System.out.println("等待hr给离职申请书"); } } } } // 测试代码 public static void main(String[] args){ AnnotationConfigApplicatonContext context = new AnnotationConfigApplicationContext("com.example.demo.observer.design"); //从spring容器中获取对应bean的实例 LoopObserverImpl loopObserver = context.getBean(LoopObserverImpl.class); ManageListener mal = context.getBean(ManageListener.class); SupervisorListener sul = context.getBean(SupervisorListener.class); GeneralListener gel = context.getBean(GeneralListener.class); //向观察者中注册listener loopObserver.registerListener(mal); loopObserver.registerListener(sul); loopObserver.registerListener(gel); VacationDataEvent vacationDataEvent = new VacationDataEvent(); vacationDataEvent.setMsg("请假"); vacationDataEvent.setDays(3); //发布请假事件,通知监听者 loopObserver.notifyListener(vacationDataEvent); }
如果想改造为异步形式,可以在观察者中引入线程池与阻塞队列。
/** * 启动一个线程循环阻塞队列的观察者,可以实现解耦异步。 */ @Component public class QueueObserverImpl implements ObserverInterface<MyListener> { //监听者的注册列表 private List<MyListener> listenerList = new ArrayList<>(); //创建一个大小为10的阻塞队列 private BlockingQueue<DataEvent> queue = new LinkedBlockingQueue<>(10); //创建一个线程池 private ExecutorService executorService = new ScheduledThreadPoolExecutor(1, r -> { Thread t = new Thread(r); t.setName("com.kangarooking.observer.worker"); t.setDaemon(false); return t; }); // private ExecutorService executorService = Executors.newFixedThreadPool(1); @Override public void registerListener(MyListener listener) { listenerList.add(listener); } @Override public void removeListener(MyListener listener) { listenerList.remove(listener); } @Override public void notifyListener(DataEvent event) { System.out.println("向队列放入DataMsg:" + event.getMsg()); queue.offer(event); } @PostConstruct public void initObserver() { System.out.println("初始化时启动一个线程"); executorService.submit(() -> { while (true) { try { System.out.println("循环从阻塞队列里面获取数据,take是阻塞队列没有数据就会阻塞住"); DataEvent dataMsg = queue.take(); System.out.println("从阻塞队列获取到数据:" + dataMsg.getMsg()); eventNotify(dataMsg); } catch (InterruptedException e) { e.printStackTrace(); } } }); } private void eventNotify(DataEvent event) { System.out.println("循环所有的监听者"); for (MyListener myListener : listenerList) { myListener.onEvent(event); } } }
上述例子看起来很牵强,没错就是为了体验本设计模式故意玩的,但若是加入下一个事件(团建),阁下怎么应对呢?
// 团建事件--事件的实现类 public class ActivityDataEvent extends DataEvent{ private String activity; } // Listener顶级接口,为了抽象Listener public interface MyListener{ void onEvent(DataEvent event); void onEventTwo(DataEvent event); } // 剩下的当然是总经理提出要团建的想法,各位兄弟接收到消息立刻反馈出各自活动名,但是由于经费不足 // 只能改为周六免费加班一天的狗血剧情啦!
十五、模板模式
模板模式是一种行为型模式,指在父类中定义处理流程的框架,将具体实现滞后到具体子类中。
主要角色:
Abstract(抽象类):声明模板方法中要用的抽象方法及定义模板方法的实现流程。
Concrete(具体实现类):实现抽象类中定义的抽象方法。
// 媳妇要喝咖啡 // 抽象类 public abstract class DrinkCoffee{ // 选择容器(悲剧的开始) public abstract void chooseContainer(); // 选择工具(入口的难题) public abstract void chooseTool(); // 选择冷却时间(破冰的坚忍) public abstract void chooseCoolTime(); // 有人选择喝coffee public void peopleDrinkCoffee(){ this.chooseContainer(); this.chooseTool(); this.chooseCoolTime(); } } // 具体实现类 // 媳妇 public abstract class WifeDrinkCoffee{ // 选择容器(悲剧的开始) @Override public void chooseContainer(){ System.out.println("夜光杯"); }; // 选择工具(入口的难题) @Override public void chooseTool(){ System.out.println("朴实无华的鎏金勺"); }; // 选择冷却时间(破冰的坚忍) @Override public void chooseCoolTime(){ System.out.println("静置3秒后,让老公喝一口,静置3分钟后,老公喝一口,静置10分钟后, 老婆喝完"); }; } // 残酷例子就不举了,还是回家吧,下雨收衣服啦
过于简单、残酷,不予以总结。
未完待续。。。