zoukankan      html  css  js  c++  java
  • 设计模式(七):命令模式

    这个模式我在书上(JavaScript设计模式)的那个章节来来回回看了几遍,有两个关键点并没有说清楚,导致尽管表面上是很简单明了,但本质没有说清,以下是书上的例子。

    书中淡解

    例子(改前):

    var carManager = {
         // request information
         requestInfo: function( model, id ){
           return "The information for " + model + " with ID " + id + " is foobar";
         },
         // purchase the car
         buyVehicle: function( model, id ){
           return "You have successfully purchased Item " + id + ", a " + model;
         },
         // arrange a viewing
         arrangeViewing: function( model, id ){
           return "You have successfully booked a viewing of " + model + " ( " + id + " ) ";
         }
    };
    carManager.arrangeViewing("Ferrari", "14523" );
    carManager.requestInfo("Ford Mondeo", "54323" );
    carManager.requestInfo("Ford Escort", "34232" );
    carManager.buyVehicle("Ford Escort", "34232" );

    例子(改后,命名模式):

    carManager.execute = function ( name ) {
        return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) );
    };
     
    carManager.execute( "arrangeViewing", "Ferrari", "14523" );
    carManager.execute( "requestInfo", "Ford Mondeo", "54323" );
    carManager.execute( "requestInfo", "Ford Escort", "34232" );
    carManager.execute( "buyVehicle", "Ford Escort", "34232" );

    我想不明白,凭什么加上这个方法,就得到了优化,哪里就解耦了。

    当carManager的API改变时候,调用这些API的对象当然都需要做修改,无论是改前、或者改后的代码写法。

    PS:所以感觉例子不当。

    网上见解

    我带着疑问,放下书本,在网上寻找资料。我发现JavaScript实现的命令模式,都是类似上面的,而其他面向对象语言的实现,就是正正经经的按照模式的类图(如下)。于是,我就奇怪了,为什么JavaScript和面向对象的例子区别这么大,按理说模式应该与实现语言无关,特别是理论部分,更没有说到一块去(大部分)。

    • 客户(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。

    • 命令(Command)角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。

    • 具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现Execute()方法,负责调用接收考的相应操作。Execute()方法通常叫做执方法。

    • 请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。

    • 接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

    例子:

    public interface Command {
        public void execute();
    }
     
    public class ConcreteCommand implements Command {
     
        private Receiver receiver = null;
        private String state;
     
        public ConcreteCommand(Receiver receiver){
          this.receiver = receiver;
        }
        public void execute() {
          receiver.action();
        }
    }
     
    public class Receiver {
        public void action(){
          //真正执行命令操作的功能代码
        }
    }
     
    public class Invoker {
        private Command command = null;
     
        public void setCommand(Command command) {
          this.command = command;
        }
     
        public void runCommand() {
          command.execute();
        }
    }
     
    public class Client {
        public void assemble(){
          //创建接收者
          Receiver receiver = new Receiver();
          //创建命令对象,设定它的接收者
          Command command = new ConcreteCommand(receiver);
          //创建Invoker,把命令对象设置进去
          Invoker invoker = new Invoker();
          invoker.setCommand(command);
        }
    }

    我的见解

    首先命令(Command)模式是行为设计模式。

    定义:

    命令模式是将方法调用、请求或操作(Receiver类里的方法)封装到一个中间者(command类),供调用者(Invoker)调用。调用者不需要知道接收者的任何接口。

    例子:

    Command模式的代码都是针对图形界面的,它实际就是菜单命令,我们在一个下拉菜单选择一个命令时,然后会执行一些动作。

    将这些命令封装成在一个类中,然后用户(调用者)再对这个类进行操作,这就是Command模式。换句话说,本来用户(调用者)是直接调用这些命令的,如菜单上打开文档(调用者),就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔离,基本没有关系了。

    简而言之,本来是调用者直接调接收者代码的,不过Command模式在两者间加了一层中间者,中间者封装接收者动作,调用者直接调中间者。

    使用场景:

    1. 图形界面的菜单命令。

    2. 需要支持命令的撤消(undo)。

    优点:

    1. 解耦了发送者和接受者之间联系。发送者调用一个操作,接受者接受请求执行相应的动作,因为使用Command模式解耦,发送者无需知道接受者任何接口。

    2. 它能实现Undo功能。每个具体命令都可以记住它刚刚执行的动作,并且在需要时恢复。

    缺点:

    滥用设计模式的带来的弊端而已。

    总结

    在仔细查阅资料后,关于上面面向对象语言和JavaScript的各自实现例子,我认为面向对象语言是更为准确,而JavaScript是不恰当的。JavaScript的例子根本没有做到接收者与调用者的解耦,虽然carManager.execute看起来像中间者,但调用者需要知道接收者里面的接口,这里是耦合了。所以,JavaScript实例看看就算了,并不正确

    另外有篇文中讲的,设计模式一个"通病":好象喜欢将简单的问题复杂化,喜欢在不同类中增加第三者,当然这样做有利于代码的健壮性、可维护性、还有复用性。这一点也有同感。

    参考文献

    1. http://www.jdon.com/designpatterns/command.htm (设计模式之Command

    2. http://www.cnblogs.com/zhenyulu/articles/69858.html (命令(Command)模式

    本文为原创文章,转载请保留原出处,方便溯源,如有错误地方,谢谢指正。
  • 相关阅读:
    #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    互联网地址处理例程
    Android系统工程模式启动过程详解
    知识填充
    git 本地回退
    理解JS中的Promise对象
    MySQL server version for the right syntax to use near 'identified
    尾递归要注意的点
    事件捕获和事件冒泡的理解
    v 2ra-y_build_a_sever_in_vltru
  • 原文地址:https://www.cnblogs.com/lovesong/p/5605076.html
Copyright © 2011-2022 走看看