命令模式:闪耀一些光

时间:2015-09-11 20:59:35

标签: javascript design-patterns

我正在探索命令模式,并且我试图弄清楚这种模式的实际好处。
我读过以下文章:https://www.safaribooksonline.com/library/view/learning-javascript-design/9781449334840/ch09s08.html
在长时间盯着它之后,我仍然没有看到实施的好处。让我澄清一下我无法得到的东西。

我们有以下命令对象:

(function(){

  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.execute = function ( name ) {
    return CarManager[name] && CarManager[name].apply( CarManager, [].slice.call(arguments, 1) );
};

文章说这是我们想要实现的目标:

CarManager.execute( "buyVehicle", "Ford Escort", "453543" );  

解释是我遇到的问题:

  

看一下上面的代码,调用我们的代码是微不足道的   通过直接访问对象的CarManager方法。我们都会   原谅我认为这没有任何问题 - 技术上,   它是完全有效的JavaScript。然而,有一些情况   这可能是不利的。

     

例如,想象一下CarManager背后的核心API是否发生了变化。   这将要求所有对象直接访问这些方法   我们的申请也要修改。这可以被视为一个层   耦合,这有效地违背了OOP的方法论   尽可能松散地耦合物体。相反,我们可以解决   通过进一步抽象API来解决这个问题。

我未能看到的是这个解决方案在任何方面都有益于:

CarManager.buyVehicle("Ford Escort", "453543");  

它们是什么意思"如果核心API"变化?我假设他们正在讨论界面,即。命令对象的方法及其实现。但是,如果它们中的任何一个发生变化,它似乎不会改变调用方法的方式(无论是否使用执行,如果方法名称发生变化,两者都不起作用)。
另外,我不知道execute方法如何解耦任何东西。无论是调用execute,还是直接执行方法,调用对象都需要引用命令对象。
此外,在文章(参见视觉方案)中,他们提到了客户端,接收器,调用者和命令对象。在示例中,我只看到两个对象(?)。

有人可以开导我吗?

3 个答案:

答案 0 :(得分:3)

使用.execute('methodName', ...),您可以更改基础方法名称,而不会影响其公共接口。

CarManager.execute('buyVehicle', 'Ford Escort')

实际上可能会调用

this.purchase(car)

引擎盖下。

那就是说,我从来没有在野外见过execute。但是,您可以在许多jQuery插件中看到这种模式,因为它允许插件只占用fn命名空间中的一个位置但执行大量命令。前var date = $('#myEl').datepicker('getDate')

答案 1 :(得分:2)

我认为这个解释忽略了这一点。 command pattern用于统一方法调用(" action"),以便您可以通过编程方式处理它们。例如,您可以将命令名称存储在一个数组中,然后在彼此之后执行它们,或者在底层API(execute函数)中执行它们,您可以将它们记录下来并存储它们以进行重放。

当然,JS已经非常动态了,这并没有太大的改变(你总是可以使用括号表示法按名称执行方法),但是你可以将方法名称作为字符串提供给execute函数,因此您可以使用它来执行某些操作 - 否则您需要使用ES6代理。

如果API发生变化,使用它的代码当然也需要改变。那个execute方法甚至可能适得其反,因为不能立即明确字符串参数是需要改变的方法名称(重构工具不会这样),甚至可能不会抛出使用错误的名称调用它时出现异常。

我想这篇文章试图在这里做的一点是,当你已经有了这个命令模式时,外观更容易实现。您可以通过编程方式处理方法名称和参数。

我们假设buyVehicle方法更改为buyCar方法。您之前通过

提供向后兼容性的位置
CarManager.buyVehicle = CarManager.buyCar;

你可以使用命令模式插入行

if (name == "buyVehicle")
    name = "buyCar";
execute方法中的

。没有太大的优势,但它可能适用于更复杂的案例。

答案 2 :(得分:1)

一些一般性的想法:

1)命令模式允许您定义一个单一的入口点"采取某种行动。

2)构建用户GUI的简洁方法是:收集给定命令所需的所有内容并执行它。从命令结构中创建菜单结构......

3)可以从您想要的任何地方调用此操作。您不必使用特殊类的实例。

4)这是一种非常严格的方式来绑定权利并强制任何行动传递给定路线。

5)此外,这种解耦方法允许您定义宏和某种脚本化过程"。不知道你是否曾经使用过MsAccess。那里的宏编码可以被称为"命令模式"。