最近给大家分享了一系列关于设计模式的文章。一个学妹问我,命令模式、策略模式、工厂模式有什么区别?代码的实现有没有区别?我说:文章可能有点长,大家多多包涵,有兴趣和大家分享策略模式和工厂模式的同学可以再温习一遍。今天我们就重点分析一下命令模式,然后看看它们的区别。?命令模式定义提供了统一的方法来封装命令,通过参数条件判断选择执行哪个命令动作。允许将每个命令存储在队列中。整体结构图如下:结构图中重要角色说明:Command(命令类):定义了命令的抽象封装类。ConcreteCommand(具体命令类):实现Command类,说白了就是具体命令的实际实现类。Receiver:与执行命令关联的操作类。Invoker(调用者):触发命令类,即外部操作事件触发执行。客户端(client):实例化一个特定的命令对象和接收者的实际类。整个结构其实看起来很难理解,但是既然是学习设计模式,就必须对每一个设计模式都有一个了解,以提高自己的知识水平。为了加深大家的理解,我还是举个通俗易懂的例子:大家一定对中国古代的君主制不陌生。皇帝可以允许在他手下侍奉的岳父领受或分发奏章。其实个人觉得这里可以体现命令模式。岳父相当于命令模式的接收者(Receiver)。执行皇帝的命令,接受早奏(ConcreteCommand)或颁布圣旨(ConcreteCommand)。皇帝相当于命令模式的旧统治者(Invoker)。酒吧!//定义命令类publicinterfaceCommand{//执行方法voidexecute();}//定义receiver-father-in-law的作用publicclassReceiver{publicvoidCharge(){System.out.println("ReceiveMemorial");}publicvoidIssue(){System.out.println("颁发圣旨");}}//具体命令类一,接收纪念命令publicclassConcreteCommandOneimplementsCommand{//Receiver,这里可以理解为岳父privateReceiverreceiver;publicConcreteCommandOne(Receiverreceiver){this.receiver=receiver;}@Overridepublicvoidexecute(){//接收纪念receiver.Charge();}}//具体命令类二,颁布圣旨publicclassConcreteCommandTwoimplementsCommand{//Receiver,这里可以理解为public-publicprivateReceiver接收器;publicConcreteCommandTwo(Receiverreceiver){this.receiver=receiver;}@Overridepublicvoidexecute(){//Issuereceiver.Issue();}}//调用者,皇帝publicclassInvoker{privateCommandcommand;publicInvoker(Commandcommand){this.command=command;}//需要执行的命令thistimepublicvoidaction(){command.execute();}}//测试demopublicstaticvoidmain(String[]args){//实例化一个岳父接收者Receiverreceiver=newReceiver();//岳父目前可以接收几个命令触发执行方法Invokerinvoker=newInvoker(commandOne);invoker.action();//result:收到一个纪念Receiver(岳父)的选择可以决定执行什么命令。这其实就是命令模式的一个简单体现。细心的同学不知道有没有发现问题。在定义中,允许每个命令存储在一个队列中。我们这里不去体现队列,其实这个实现也很简单。在main方法中添加一个队列就可以了。publicstaticvoidmain(String[]args){//实例化一个岳父接收者Receiverreceiver=newReceiver();//岳父目前可以接收几个命令CommandcommandOne=newConcreteCommandOne(receiver);CommandcommandTwo=newConcreteCommandTwo(receiver);//存储命令Queuequeue=newLinkedList<>();queue.add(commandOne);queue.add(commandTwo);//批量执行for(Commandcommand:queue){Invokerinvoker=newInvoker(command);invoker.action();}}这里想给大家做一个扩展点,也是之前看到的验证写法。实际工作中肯定会遇到很多接口验证。这个验证逻辑怎么写,怎么实现代码复用、抽象等等,这其实是一个比较难的问题!大致看一下它的结构图!!!演示代码,我也写出来给大家。需要注意的是,我们需要在ApplicationContextAware中实现afterPropertiesSet方法。//定义抽象验证方法publicabstractclassValidatePlugin{publicabstractvoidvalidate();}//抽象规则执行器publicabstractclassValidatePluginExecute{protectedabstractListgetValidatePlugins();publicvoidexecute(){finalListvalidatePlugins=getValidatePlugins();tils)validate){returns;}for(ValidatePluginvalidatePlugin:validatePlugins){//执行验证逻辑,这里可以根据自己的实际业务场景修改validatePlugin.validate();}}}//具体测试规则@Component("validatePluginOne")publicclassValidatePluginOneextendsValidatePlugin{@Overridepublicvoidvalidate(){System.out.println("validatePluginOneruleverification");}}//具体执行器,将要执行的规则添加到validatePlugins@Component("testValidatePlugin")pertiesSet(){//添加规则validatePlugins=Lists.newArrayList();validatePlugins.add((ValidatePlugin)this.applicationContext.getBean("validatePluginOne"));}@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{this.applicationContext=applicationContext;}@OverrideprotectedList(ValidatePlugin>get{returnthis.validatePlugins;}}//测试demopublicstaticvoidmain(String[]args){ApplicationContextapplicationContext=newClassPathXmlApplicationContext("classpath:applicationContext.xml");TestValidatePlugintestValidatePlugin=(TestValidatePlugin)applicationContext.getBean("testPluginatePluginate");exeValidatePlugintest;}这是只是一个简单的测试demo,为了让大家有个思路,设计模式不一定是照搬代码,而是要开阔自己的视野,提高自己解决问题的能力。对于一些不同的接口,我们只需要添加具体验证规则在TestValidatePlugin中,整体的扩展性会更高,看起来也会更高大上。所以w上面说的命令模式、策略模式、工厂模式有什么区别?命令模式:属于行为设计模式。在命令模式下,不同的命令在执行过程中会产生不同目的的结果,不同的命令是不可替代的。策略模式:属于行为设计模式。在策略模式中,重点是每一个策略的实现,解决根据运行时状态从一组策略中选择不同策略的问题。工厂模式:属于创作设计模式。在工厂模式中,重点是封装对象的创建过程。这里的对象不受任何业务场景的限制。它们可以是策略,但也可以是其他东西。那么对于设计模式,其实我的理解只是为了说明一个问题,不同的设计模式都是为了应对不同的场景而设计的,不同的业务场景有不同的写法。中介模式中介模式,看名字就可以理解,定义了一个中间结构,方便下游组织的管理。那么什么是中介模式呢?GoF中的《设计模式》是这样解释的:中介模式定义了一个单一的(中介)对象来封装一组对象之间的交互。将一组对象之间的交互委托给一个中间对象,避免对象之间的直接交互。我们再看一下这个结构图:Mediator(抽象中介):用来定义参与者和中介之间的交互方式ConcreteMediator(具体中介):实现中介定义的操作,即实现交互方式。Colleague(抽象同事角色):抽象类或接口,主要用于定义参与者如何交互。ConcreteColleague(有同事的作用):很简单,就是Colleague中方法的具体实现。上面的结构定义来自于设计模式之美。看这个结构图,其实和我之前给大家写的观察者模式有点相似。有兴趣的同学可以再复习一遍。作为一个老规矩,让我们给出一个示例代码来实现高铁系统。要知道有一个调度中心来控制每一列高铁进站的顺序。你们需要互相沟通。假设其中一列火车无法通信,将发生不可估量的错误。因此,需要通过调度中心来处理通信逻辑,同时管理当前有多少车辆在等待进站。//抽象参与者,也可以使用抽象写法publicinterfaceColleague{//通信消息voidmessage();}//抽象中介publicinterfaceMediator{//定义处理逻辑voiddoEvent(Colleaguecolleague);}//具体参与者@ComponentpublicclassMotorCarOneColleagueimplementsColleague{@Overridepublicvoidmessage(){//模拟处理业务逻辑System.out.println("高铁一号收到消息!!!");}}@ComponentpublicclassMotorCarTwoColleagueimplementsColleague{@Overridepublicvoidmessage(){System.out.println("高铁高铁2号收到消息!!!");}}@ComponentpublicclassMotorCarThreeColleagueimplementsColleague{@Overridepublicvoidmessage(){System.out.println("高铁3号收到消息!!!");}}//具体中介@ComponentpublicclassDispatchCenterimplementsMediator{//管理有哪些参与者@AutowiredprivateListcolleagues;@OverridepublicvoiddoEvent(Colleaguecolleague){for(Colleaguecolleague1:colleagues){if(colleague1==colleague){//如果是高铁信息本身,可以处理其他业务逻辑//doSomeThing();continue;}//通知其他参与的colleagues1.message();}}}//测试demopublicstaticvoidmain(String[]args){//初始化spring容器ApplicationContextapplicationContext=newClassPathXmlApplicationContext("classpath:applicationContext.xml");//获取中介,调度中心DispatchCenterdispatchCenter=(DispatchCenter)applicationContext.getBean("dispatchCenter");//否。1高铁发消息出去MotorCarOneColleaguemotorCarOneColleague=(MotorCarOneColleague)applicationContext。getBean("motorCarOneColleague");//通过调度中心通信信息dispatchCenter.doEvent(motorCarOneColleague);//结果:高铁3号收到消息!!!//高铁2号收到消息!!!//2号高铁发消息出去MotorCarTwoColleaguemotorCarTwoColleague=(MotorCarTwoColleague)applicationContext.getBean("motorCarTwoColleague");dispatchCenter.doEvent(motorCarTwoColleague);//结果:1号高铁收到消息!!!//高铁3号收到消息!!!}即使完成了中介模式的demo代码,通过这个demo你应该可以发现,中介还是很容易理解的,但是中介的应用场景还是比较少见。对于一些严重依赖类似网络结构的类,改形成类似蒲公英的结构,从中间向外扩散,达到解耦的效果。在UI界面控件中比较常见。当然Java中的java.util.Timer也可以理解为中介者模式,因为它可以控制内部线程如何运行,比如运行频率。上面说了,中介模式和观察者模式非常相似,通过demo代码也可以发现这一点。在观察者模式中,观察者和被观察者基本是固定的,而在中介模式中,观察者和被观察者总是固定的。不固定,中介可能最终成为一个巨大的原始类。总结一下命令模式:虽然不是很常见,但是我们还是要分清楚它和工厂模式、策略模式有什么区别,应用场景是什么,它能给我们带来什么思考。比如我上一个例子,命令模式可以实现命令的存储。本质就是把命令维护在一个队列中,那我们为什么不能在我们的业务代码中也通过一个数组来维护一些接口验证依赖,里面存放的是需要的Validatedbean实例。提高代码的可重用性和可扩展性。中介模式:一般来说这个不太适用。虽然可以解耦对象,但是也有副作用,我们在实际业务场景中很少遇到这样的场景。了解实现原理即可。至于和observers的区别,上面说了,更多的我们可能一直在使用一些中间件消息队列来进行处理。我是敖丙,知道的越多,不知道的越多,我们下期再见!