问题 揭示模块模式的缺点


我最近熟悉了Revealing Module模式,并且我已经阅读了很多关于它的文章。

这似乎是一个非常好的模式,我想在我拥有的一个大项目中开始使用它。在我正在使用的项目中:Jquery,KO,requirejs,Jquery Mobile,JayData。在我看来它似乎非常适合KO ViewModels。

具体我想用 这个 它的版本。

我找不到的一件事是使用这种模式的缺点,是因为没有(我觉得很难相信)?

在开始使用它之前我应该​​考虑什么?


12191
2017-12-27 07:03


起源

查看这篇文章: addyosmani.com/resources/essentialjsdesignpatterns/book/... 最后有一个缺点部分。 - nemesv
最终模块模式还克服了模块模式和显示模式的一些缺点(例如与return语句的紧密耦合,如何声明公共和私有函数,私有和公共子例程的非声明性命名空间,以及对象文字的混合使用与return语句): github.com/tfmontague/definitive-module-pattern - tfmontague


答案:


Revealing Module Pattern(RMP)创建的对象在覆盖方面表现不佳。因此,使用RMP制作的对象不能很好地用作原型。因此,如果您正在使用RMP来创建将在继承链中使用的对象,那就不要这样做。 这种观点是我自己的,与那些揭示原型模式的支持者相对立。

要查看错误的继承行为,请使用以下url构建器示例:

function rmpUrlBuilder(){
  var _urlBase = "http://my.default.domain/";
  var _build = function(relUrl){
    return _urlBase + relUrl;
  };

  return {
    urlBase: _urlBase,
    build: _build
  }
}

撇开为什么要将RMP用于没有私有组件的对象的问题,请注意,如果您获取返回的对象并使用“覆盖urlBase”http://stackoverflow.com“,你会期望build()的行为适当地改变。它不会,如下所示:

var builder = new rmpUrlBuilder();
builder.urlBase = "http://stackoverflow.com";
console.log(builder.build("/questions"); // prints "http://my.default.domain/questions" not "http://stackoverflow.com/questions"

将行为与以下URL构建器实现进行对比

function urlBuilder = function(){
  return {
    urlBase: "http://my.default.domain/".
    build: function(relUrl){ return this.urlBase + relUrl;}
  }
}

var builder = new urlBuilder();
builder.urlBase = "http://stackoverflow.com";
console.log(builder.build()); // prints "http://stackoverflow.com/questions"

行为正确。

您可以使用此范围更正显示模块模式的行为,如下所示

function rmpUrlBuilder(){
  var _urlBase = "http://my.default.domain/";
  var _build = function(relUrl){
    return this.urlBase + relUrl;
  };

  return {
    urlBase: _urlBase,
    build: _build
  }
}

但这相当违背了揭示模块模式的目的。有关详细信息,请参阅我的博文 http://ilinkuo.wordpress.com/2013/12/28/defining-return-object-literals-in-javascript/


14
2017-12-31 11:33





我读过@nemesv引用我的文章(谢谢:))我认为还有一个未提及的缺点,所以我想我会在这里添加它以供参考。以下是文章的引用:

缺点

这种模式的缺点是如果私有函数引用   一个公共函数,如果一个补丁,公共函数不能被覆盖   是必要的。这是因为私人功能将继续   引用私有实现,该模式不适用于   公共成员,只有功能。

引用私有变量的公共对象成员也是   受上述无补丁规则说明的约束。

因此,使用Revealing Module模式创建模块   可能比使用原始模块创建的更脆弱   模式,所以在使用过程中应小心。

而我的补充:

您不能对此模式使用继承。例如:

var Obj = function(){
    //do some constructor stuff
}

var InheritingObj = function(){
    //do some constructor stuff
}

InheritingObj.prototype = new Obj();

InheritingObj.prototype.constructor = InheritingObj;

这是一个简单的例子,用于在js中继承,但在使用时 揭示原型模式 你需要这样做:

InheritingObj.prototype = (function(){
    //some prototype stuff here
}());

这会覆盖你的继承。


4
2017-12-31 07:14



它似乎与Object.create(urlBuilder)完美配合;另一种继承方式就是这种方式 jsfiddle.net/d0n7kfmx 你怎么看? - user2734550


Revealing Module Pattern的其他缺点包括:

  1. 公共函数与Return语句紧密耦合
  2. 公共函数的对象文字和私有函数的独立声明的混合使用

我建议在Revealing Module Pattern上使用Definitive Module Pattern (https://github.com/tfmontague/definitive-module-pattern


-2
2017-07-07 08:40



我不推荐这种模式,因为它与揭示模块模式没有实质性的不同。它在覆盖和原型方面具有与接受的答案相同的缺点。 - I-Lin Kuo
问题是关于Revealing Module模式的缺点。这不是关于使用模块模式的决定。 - tfmontague