日期:2014-05-16 浏览次数:20416 次
?
大多数简单的页面应用,js可以写得较为自由随意,但涉及对象众多,关系复杂的 One Web Page 企业应用,
?
常常需要考虑如何降低js对象间的耦合,那种“你中有我,我中有你”的代码编写方式,会让维护人员无法接手。
?
因为工作关系,我曾接手过一个包含数千行js代码的项目。该项目的开发团队在国外,当时也还处于开发阶段。
?
缺少文档,遇到问题只能发邮件询问国外的开发团队,时间长了他们也烦,只好自己静下心来看代码。
?
细看后发现js的架构共有三层:底层是dojo,中间是记录用户行为和通信的可配置框架,顶层是业务逻辑,
?
项目中的js文件全部由 eval 方法以字符串的形式动态加载到浏览器上运行,无法用firebug或chrome调试。
?
所幸的是这些js代码采用了函数式的面向对象编程风格,结构清晰,包含了众多模板和动态加载的配置文件。
?
因此我才能较快地掌握代码的来龙去脉。低耦合的代码有助于维护和扩展,这是大多数人的共识。
?
对于没有接口,没有继承,没有抽象类的js来说,“事件机制”能简单有效地降低js模块间的耦合。
?
下面的代码是“事件”机制的示例:
?
?
//定义树节点 var TreeItem = function(){ //利用闭包创建的私有数组,用来保存所有监听树节点展开状态变化的事件 var expandingChangedListenerList = []; var expanded = false; //私有方法:当树节点的展开状态发生变化时,调用监听器数组中的所有监听方法 function fireExpandingChangedEvent(){ //遍历数组中的所有监听器 for(var i=0; i<expandingChangedListenerList.length; i++){ var listener = expandingChangedListenerList[i]; var event = { //创建事件对象,包含调用监听方法所需要的参数 button: 0 } listener(event); // 执行监听器方法 } } //公共方法:向树节点对象添加监听事件 this.addExpandingChangedListener = function(listener){ if(listener && typeof(listener) == 'function'){ expandingChangedListenerList.push(listener); } } //公共方法:当树节点的展开状态变化时,调用所有的监听器方法 this.setExpanded = function(isExpanded){ if(expanded != isExpanded){ expanded = isExpanded; fireExpandingChangedEvent(); } } } ///////////////////////////////////// //实例化一个树节点 var treeItem = new TreeItem(); // 定义一个属性窗口对象,向树节点treeItem注册一个展开状态变化监听器 // 如果树节点的展开属性发生变化,属性窗口会输出一段字符 var PropertiesView = { init: (function(){ var listener = function(event){ if(event && event.button == 0){ console.log('Do something here for the changed status of tree item.'); } }; treeItem.addExpandingChangedListener(listener); })() }; // 改变树节点treeItem的展开状态,则注册其上的所有监听器将被调用 treeItem.setExpanded(true);?
上述“事件机制”将不同模块间的事件响应代码留在自身,被监听者不需要知道谁在监听它,也不需知道监听者随后的行动。
?
而监听者也不需要知道自己定义的监听方法在什么时候,以及在何种情况下会被调用,只要注册到正确的对象上即可。
?
事件的相关各方都减少了对对方知识的掌握,从而降低了耦合。
?
需要注意的是,“零耦合”的情况是不存在的:上述代码中,作为事件监听者的PropertiesView,
?
以及作为事件被监听者的treeItem,二者间仅有的耦合性,集中在event 对象上。
?
因此各类 Event 事件对象,需要在代码的显要部分,公开地定义出来,以供查阅修改,甚至使用模板或配置文件?。
?
这也正是所有解耦合设计的终极目地:将耦合暴露在阳光下,而不是隐藏在阴暗的角落。
?
?
?