帮助“可扩展的JavaScript应用程序架构”

时间:2011-04-21 05:59:13

标签: javascript design-patterns publish-subscribe

我正在构建一个大型的javascript应用程序,我决定使用Nicholas Zakas的可扩展应用程序架构设计: http://developer.yahoo.com/yui/theater/video.php?v=zakas-architecture

根据他的系统,模块是自封装的,彼此不了解......但是我在项目中遇到了很多实例,模块似乎需要彼此了解,因为它们本质上是,一个更大的整体的个别部分。

例如..我有三个模块:上传,窗口和管理器。

点击上传选项时,会打开一个带有上传表单的弹出窗口。 “经理”窗口上还有一个链接。

单击管理器链接会更新弹出窗口以显示管理工具...

...

这对我来说是最有意义的(伪代码):

upload module:
  upload option click --> sandbox.notification('need pop up window', [...html markup for form...])

manager module:
  manager link click --> sandbox.notification('need pop up window', [...html markup for admin tools...])

window module:
  sandbox.listen('need pop up window') --> calls createPopUpWindow( passed in html markup  )

...然而这违背了哲学原因,因为上传和管理模块专门“请求”窗口模块做某事,因此他们知道它......

所以,我能想到的另一种方法是:

upload module:
  upload option click --> sandbox.notification('upload option clicked', [...html markup for form...])

manager module:
  manager link click --> sandbox.notification('manager link clicked', [...html markup for admin tools...])

window module:
  sandbox.listen('upload option clicked') --> calls createPopUpWindow( passed in html markup  )
  sandbox.listen('manager link clicked') --> calls createPopUpWindow( passed in html markup  )

..但是这感觉不那么直观了,说实话,我认为它使我的代码不太清楚,因为查看上传模块的通知'上传选项点击',并没有告诉我这应该是什么当它被点击时发生..我必须在所有其他文件中搜索正在监听它的模块.....我猜这可以被视为一个好处,因为多个模块可能想要响应'上传选项点击','需要弹出窗口'显然只能由一个模块解决。

但是当采用这种方法时,让我的上传模块传递一堆关于它不知道的弹出窗口的html标记对我来说开始变得不那么有意义了,它开始看起来像窗口模块应该负责生成该标记---但是很多标记都是“上传”特定的,并且标记具有绑定到上传模块中的函数的事件监听器---所以在窗口模块中具有该标记不是真的很合乎逻辑......所以它开始变得非常令人困惑,因为什么是构建所有这些的最佳方法。

我还有另一种情况甚至更成问题。两个模块:Track和Container。容器有许多轨道,最初我只是在容器模块的内部部署了轨道功能 - 但随着模块中代码的长度开始增长,我决定将它们分离为自己的模块,以便清洁代码。无论如何,因为容器需要知道它的轨道并且能够在内部引用它们,我能设置它的唯一方法就是:

containerObject = function(name) {
    this.name                       = name;
    this.video_track                = {'name': 'video',   'markup': sandbox.notification('create-track', 'video')}
    this.audio_track                = {'name': 'audio_1', 'markup': sandbox.notification('create-track', 'audio')}
    ....etc....
};

因此Track模块正在执行sandbox.listen('create-track')并将其指向一个函数,该函数返回给定类型的新轨道对象.....也许它不值得拥有轨道是它自己的模块......因为这是我根据通知电话分配值的唯一地方。

我很想听听熟悉pub / sub架构的其他程序员对这个话题的看法......

请告诉我你的想法&建议。

谢谢。

1 个答案:

答案 0 :(得分:11)

有许多模式可以处理对象间通信 - 这就是你真正的问题所在:沟通。

您的问题可以归纳为:

  1. 您希望将功能细分为模块
  2. 您希望模块尽可能自包含,尽可能少地使用外部链接
  3. 模块需要在“宏观方案”中使用其他模块,但
  4. No.3是给你带来问题的 - 你希望模块是独立的,但是它需要与其他模块通信才能使你的程序正常工作。

    典型的解决方案是让模块向外界开放“标准化”的沟通渠道。它不应该关心(或重要)那些通道的另一侧有多少,哪个,哪里或哪些对象。它只接收来自输入通道的命令,并向输出通道发送通知。一个很好的副作用是能够轻松地对模块进行单元测试。

    请注意,您的模块不应该关心另一方 - 四个W

    什么 - 不应该关心它正在谈论什么类或对象(或听)

    在哪里 - 不应该关心对方的位置(服务器?或在同一浏览器上)

    哪个 - 不应该关心它与哪个特定对象(总统,或者只是一个工人)

    多少 - 不应该关心它们同时交谈/收听的对象数量

    然后使用主配置连接整个图表。这是依赖注入背后的基本概念。

    至于管道,有几种方法/模式可以做到:

    1. 活动和处理程序
    2. 发布/订阅
    3. IOC / DI容器
    4. 上述组合