命令模式与策略模式之己见

以前项目写过关于TR069协议报文处理的代码(主要是基于SOAP协议发送一些远程命令并处理响应),在设计的时候,想的是应用策略模式对报文进行解析处理,

下图是主要代码结构(和策略模式很像)

代码类似于:

         /**
         * 1、需要解析的XML
         */
        String xml = "<xml>...</xml>";
        /**
         * 2、获取xml类型
         */
        MessageType type = SoapMessageFactory.getRpcType(xml);
        /**
         * 3、初始化soapMessage(最好先判断下xml类型)
         */
        SoapMessage soap = SoapMessageFactory.initSoap(type);
        /**
         * 4、解析xml,可通过header和body变量获取结果
         */
        soap.parse(xml);

但回过头来仔细看,这哪是什么策略模式呢,明明是更符合命令模式(message对应command,paser对应receiver),策略模式和命令模式这么相似吗,这么容易混淆?于是我就进行分析比较。

基本定义:

策略模式:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。该模式使得算法可独立于它们的客户变化。
命令模式:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

以SOAP报文解析为例,先从设计思路分析。

1、最初想法:将所有报文都统一看做为SoapMessage,定义不同的算法进行封装,对不同的报文进行不同的解析。认为是策略模式。

2、进一步:其实Soap报文根据不同的type相当于不同请求(命令),定义并封装不同的算法,是与相应的报文对应的。认为是命令模式。

第一种思路与策略模式的定义对比后就可以发现明显是不对的,因为策略模式会要求不同算法相互替换,而不同报文解析是不能替换的。

      策略模式侧重同一个问题可用不同的可替换的算法去解决,而实际使用中,说的苛刻些,调用者只取其一,执行一次算法即可;比如对数组排序,用插入排序算法排好序后,你不会再用堆排序重新拍一遍,又比如你用支付宝支付后,不会再用微信支付一遍;而这些场景都可以应用策略模式。

策略模式网上的例子很多,我觉得这篇文章总结的特别好:http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html

====================分割线===================================

而对于命令模式更多的解释是这样:不同问题使用不同算法或者侧重将请求的发送者和接收者解耦,这难道真的抓住命令模式的本质了吗?

首先看一下命令模式的UML图:

有5个角色:Invoker(调用者)和Receiver(接收者)、command接口和ConcreteCommand实现类以及Client。

       首先注明:如果对于跨进程或者跨机器的这种远程的方法调用,使用类似命令模式的这种构造方法相信没有人有异议,下面对命令模式的分析侧重单一进程。

网上很多人都使用下面的例子进行解释:

 1 class Invoker {
 2     private Command command;
 3     public Invoker(Command command) {
 4         this.command = command;
 5     }
 6     public void action(){
 7         this.command.execute();
 8     }
 9 }
10
11 abstract class Command {
12     public abstract void execute();
13 }
14
15 class ConcreteCommand extends Command {
16     private Receiver receiver;
17     public ConcreteCommand(Receiver receiver){
18         this.receiver = receiver;
19     }
20     public void execute() {
21         this.receiver.doSomething();
22     }
23 }
24
25 class Receiver {
26     public void doSomething(){
27         System.out.println("接受者-业务逻辑处理");
28     }
29 }
30
31 public class Client {
32     public static void main(String[] args){
33         Receiver receiver = new Receiver();
34         Command command = new        ConcreteCommand(receiver);
35         Invoker invoker = new Invoker(command);
36         invoker.action();
37     }
38 }

上面的代码看似和命令模式的类图很吻合,我觉得更像是为了模式而模式所拼凑出的一段代码,没有太多实际意义,甚至会误导人。这段代码最多体现了命令模式定义的前半部分:“将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化”,而即使用来说明这一部分,代码也有部分是多余的,那就是Receiver;main方法的执行过程更像一个跷跷板,Invoker翘一下Command,Command翘一下Receiver,而Receiver执不执行、什么时候执行,为什么由别的对象说了算呢?!或者直接去掉Receiver,留下Invoker,Command和ConcreteCommand,Invoker保持对Command的引用,而ConcreteCommand封装自己的特性,命令怎么执行由ConcreteCommand的逻辑确定,而这也体现了面向接口编程原则,Command依旧可独立于Invoker变化。根据上面的分析,我总结了命令模式的一种变形,称之为“简约型命令模式”。

一)简约型命令模式

UML图:

这里去掉了Receiver,Invoker持有对Command的引用,每个Command都有唯一的方法Execute()。在Client中加入了命令队列(Queue为虚线,表示可有可无),Client可以一次生成一个命令,马上执行,或者一次生成若干命令放入队列,依次执行。

这种方式真是像极了“策略模式”,这可能就是我把命令模式和策略模式混淆的原因,而这种模式不能称为策略模式,就是因为算法是不可相互替代的,称之为“简约型命令模式”。

可参考:http://www.jdon.com/designpatterns/command.htm

既然有简约型,就对应会有较复杂的类型,当然主要还是参考定义,注重实现其后半部分:“对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。”,我称之为“异步事务性命令模式”。

二)异步事务型命令模式

当然还是先看UML图:

结构与原始的命令模式基本一样,唯一修改的是Receiver对象,增加了一个pool属性,用来接收Command,Invoker每次调用命令,并不会直接执行而是先写入pool中,待Receiver等到合适时机去选择执行,这种结构把Invoker和Receiver彻底解耦,Receiver完全不受Invoker制约,也完全体现了一个Receiver的角色。入队的同时,还可以将命令持久化,以一种Write ahead log的形式对其进行记录,还有ConcreteCommand中有个state属性,很多介绍命令模式的文章对没有对其进行说明,我认为这是实现事务必不可少的(可以用来指示此命令与某些命令是一组的,要么都执行成功,要么异常回滚,或者可以结合Composite模式使用),Receiver中添加的undo()和redo()方法就是和事务相关的操作,如果服务异常退出,使用redo()方法结合wal日志进行恢复,如果事务执行中断就需要根据命令执行前的状态进行恢复。

目前还没有看到相关的实例。

最后还说一句:“不同问题使用不同算法或者侧重将请求的发送者和接收者解耦”只是命令模式的一种表现形式,解耦、不同问题不同算法,太容易让人和其他的模式相混淆,还是应该回到最初的定义去理解。

PS:最后写的有点仓促,对于这种事务设计还要继续研究
时间: 2024-08-28 05:13:00

命令模式与策略模式之己见的相关文章

【设计模式】 模式PK:命令模式VS策略模式

1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为"算法"已经是一个完整的.不可拆分的原子业务(注意这里是原子业务,而不是原子对象),即其意图是让这些算法独立,并且可以相互替换,让行为的变化独立于拥有行为的客户:而命令模式则是对动作的解耦,把一个动作的执行分为执行对象(接收者角色).执行行为(命令角色),让两者相互独立而不相互影响. 我们从一个相同的业务需

跟我学设计模式视频教程——命令模式vs策略模式,唠嗑

课程视频 命令模式vs策略模式 唠嗑 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 跟我学设计模式视频教程--命令模式vs策略模式,唠嗑,布布扣,bubuko.com

Android设计模式之命令模式、策略模式、模板方法模式

命令模式是其它很多行为型模式的基础模式.策略模式是命令模式的一个特例,而策略模式又和模板方法模式都是算法替换的实现,只不过替换的方式不同.下面来谈谈这三个模式. 命令模式 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. java中传递(注入)对象很容易,但是却不支持直接传递行为(即传递函数或者说传递方法),只能间接的通过传递(注入)一个对象,再调用它的行为来实现.如果把这样的行为抽取出来为一个类,称作命令类,它的具体实现都是命令

模式PK:命令模式VS策略模式

1.概述 命令模式和策略模式的类图确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的意图是封装算法,它认为"算法"已经是一个完整的.不可拆分的原子业务(注意这里是原子业务,而不是原子对象),即其意图是让这些算法独立,并且可以相互替换,让行为的变化独立于拥有行为的客户:而命令模式则是对动作的解耦,把一个动作的执行分为执行对象(接收者角色).执行行为(命令角色),让两者相互独立而不相互影响. 我们从一个相同的业务需

简单工厂模式和策略模式的区别

直接上代码: 简单工厂模式: ------------------------------一个抽象类   -------------------------- abstract class AbsClass { //抽象方法:提供一些列的算法操作 public abstract void acceptCash(string org); } ------------------------------2个实现类   -------------------------- //继承自抽象类 class

委派模式和策略模式

一.委派模式 委派模式(Delegate Pattern):指负责任务的调度和分配任务,跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果.(属于行为型模式,但它不属于GOF的23种设计模式之一.类名以Delegate和Dispatcher结尾的一般都是委派模式) 委派模式在Spring中应用非常多,大家常用的DispatcherServlet其实就用到了委派模式.现实生活中也常有委派的场景发生,例如:老板(Boss)给项目经理(Leader)

设计模式之桥梁模式和策略模式的区别

桥接(Bridge)模式是结构型模式的一种,而策略(strategy)模式则属于行为模式.以下是它们的UML结构图. 桥梁模式: 策略模式: 在桥接模式中,Abstraction通过聚合的方式引用Implementor. 举一个例子: 策略模式:我要画圆,要实心圆,我可以用solidPen来配置,画虚线圆可以用dashedPen来配置.这是strategy模式. 桥接模式:同样是画圆,我是在windows下来画实心圆,就用windowPen+solidPen来配置,在unix下画实心圆就用uni

【设计模式】简单工厂模式与策略模式

[前言]今天再次把<大话设计模式>一书拿出来翻了一下,对于前面一节初探中讲诉的简单工厂模式和策略模式,有了更好的理解.按照习惯,还是继续梳理梳理. [简单工厂模式]:封装(数据+算法) 简单工厂模式的特点: 每一个子类最好能做到职责单一,将每一个需要涉及的数据和算法,封装成一个独立的类. 工厂模式中的工厂类其实起到了一个调度者的角色: 2.1 工厂类可以达到将实现具体逻辑的子类隐藏的效果,只需要将自己暴露调用实例化的接口,根据工厂类提供的对外方法,在内部实现逻辑判断,并最后实例化具体的子类对象

工厂模式与策略模式之区别

设计模式有很多种,其中功能相似的很多,但是为什么还要分这么多种名字,查阅资料,我觉得下面的解释最为合理:用途不一样,名字就有区别,一把斧头用来砍人就叫凶器,用来砍柴就叫伐木斧,用来劈门就叫消防斧,这些模式的名字都是根据具体使用时的场景,联系了现实里某样东西或某种习惯而取得,所以很相似的模式行为有不同叫法. 今天我们就来研究一些工厂模式与策略模式的一些区别: 工厂模式是创建型模式,适应对象的变化. 策略模式是行为性模式,适应行为的变化 工厂模式封装对象,实例化对象后调用的时候要知道具体的方法,策略