命令模式:发光

Command pattern: shine some light

我正在探索命令模式,并试图弄清楚这种模式的实际好处。
我已阅读以下文章: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" );  

解释是我遇到的问题:

Taking a look at the above code, it would be trivial to invoke our CarManager methods by directly accessing the object. We would all be forgiven for thinking there is nothing wrong with this—technically, it’s completely valid JavaScript. There are however scenarios in which this may be disadvantageous.

For example, imagine if the core API behind the CarManager changed. This would require all objects directly accessing these methods within our application to also be modified. This could be viewed as a layer of coupling, which effectively goes against the OOP methodology of loosely coupling objects as much as possible. Instead, we could solve this problem by abstracting the API away further.

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

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

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

谁能赐教一下?

使用.execute('methodName', ...),您可以更改底层方法名称而不影响其public 接口。

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

实际上可能会打电话给

this.purchase(car)

引擎盖下。


也就是说,我从未真正在野外见过 execute。但是,您确实在许多 jQuery 插件中看到了这种模式,因为它允许插件只占用 fn 命名空间中的一个位置,但可以执行很多命令。例如 var date = $('#myEl').datepicker('getDate')

一些一般性想法:

1)命令模式允许你定义一个"single point of entry"到一个特定的动作。

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

3) 可以从任何地方调用此操作。您不一定要使用特殊 class.

的实例

4) 这是一种非常严格的绑定权限并强制任何动作沿着您给定的路线传递的方式。

5) 此外,这种解耦方法允许您定义宏和某种 "scripted process"。不知道您是否使用过 MsAccess。那里的宏编码可以称为"command patterned".

我认为这个解释没有抓住重点。 command pattern 用于具体化方法调用 ("action"),以便您可以以编程方式处理它们。例如,您可以将命令名称存储在一个数组中并紧接着执行它们,或者在底层 API(execute 函数)中您可以记录它们并存储它们以供重播。

当然,JS 已经非常动态了,这并没有太大变化(您总是可以使用方括号表示法按名称执行方法),但是您可以将方法名称作为字符串使用 execute 函数,所以你可以用它做一些事情——否则你需要一个 ES6 代理。

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

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

假设 buyVehicle 方法更改为 buyCar 方法。您以前可以通过

提供向后兼容性的地方
CarManager.buyVehicle = CarManager.buyCar;

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

if (name == "buyVehicle")
    name = "buyCar";

execute方法中。优势不大,但可能适用于更复杂的情况。