我试图弄清楚在某种情况下要遵循哪种模式。我有一个网络应用程序,它由几个以某种方式相互交互的主要小部件组成。小部件遵循模块模式。
让代码说话:
MyApp.Widgets.MainLeftBox = (function(){
var self = {};
self.doSomething = function(){
var certainState = MyApp.Widgets.MainRightBox.getCertainState();
if (certainState === 1){
console.log(‘this action happens now’);
}
else {
console.log(‘this action can’t happen because of a certain state in My.App.Widgets.MainRightBox’);
}
}
return self;
})();
如您所见,我在这里有紧密的耦合。众所周知,紧耦合是邪恶的。(除非你找到了唯一的一个!;-))
我知道通过遵循发布-订阅/自定义事件模式可以实现很多解耦。但这更适合 A 开始某事而 B 可以做出反应的情况。但我有一种情况,A 独立启动某事,但需要检查 B 的某个状态才能继续。
当我努力实现可维护性时,我正在寻找摆脱这个地狱的方法。
我首先想到的是中介模式。
但是,我的代码仍然是这样的:
MyApp.Widgets.MainLeftBox = (function(mediator){
var self = {};
self.doSomething = function(){
var certainState = mediator.getCertainState();
if (certainState === 1){
console.log(‘this action happens now’);
}
else {
console.log(‘this action can’t happen because of a certain state in mediator’);
}
}
return self;
})(MyApp.Mediator);
这样稍微好一点,因为 Widget 不直接通信,而是通过中介间接通信。
但是,我仍然觉得我做错了,必须有更好的方法来实现小部件之间的解耦。
编辑
让我总结一下到目前为止的事情!
总的来说,我确实喜欢分离视图的 MVC 方法!但是,将此示例更像是复杂的模块。从视觉上看,这些不一定是“盒子”。这种方式更容易描述。
另一个给定的事实应该是,A独立启动一个动作,然后需要检查某个状态。它无法订阅 B 的状态更改并提供操作或不提供。它必须像 A独立启动它,然后需要检查某个状态。将此视为需要 B 进行的一些复杂操作。
所以我想出了一个混合自定义事件/回调/调解器的方法,我真的很喜欢它的一些东西。
1.) 一个模块不知道任何其他模块
2.) 一个模块也不知道中介者
3.) 依赖于某些外部状态的模块只知道它依赖于某些外部状态 - 不多
4.) 模块真的不在乎谁将提供这个特定状态
5.) 模块可以确定是否已经提供了特定状态
6.) 请求管道是直的。换句话说,模块是此操作的启动器。它不只是订阅状态更改事件(请记住 A 开始操作,然后需要来自 B(或某处)的状态
我在这里发布了一些示例代码,还提供了一个 jsFiddle:http: //jsfiddle.net/YnFqm/
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
</head>
<body>
<div id="widgetA"></div>
<div id="widgetB"></div>
<script type="text/javascript">
var MyApp = {};
(function (MyApp){
MyApp.WidgetA = function WidgetA(){
var self = {}, inner = {}, $self = $(self);
//init stuff
inner.$widget = $('#widgetA');
inner.$button = $('<button>Click Me!</button>')
.appendTo(inner.$widget)
.click(function(){self.doAction();});
self.doAction = function(){
//Needs state from WidgetB to proceed
/* Tight coupling
if (MyApp.WidgetB.getState() == 'State A'){
alert('all fine!');
}
else{
alert("can't proceed because of State in Widget B");
}
*/
var state;
$self.trigger('StateNeeded',function(s){state = s});
if (state == 'State A'){
alert('all fine!');
}
else{
alert("can't proceed because of State in Widget B");
}
};
return self;
};
MyApp.WidgetB = function WidgetB(){
var self = {}, inner = {};
//init stuff
inner.$widget = $('#widgetB');
inner.$button = $('<button>State A</button>')
.appendTo(inner.$widget)
.click(function(){
var buttonState = inner.$button.text();
if (buttonState == 'State A'){
inner.$button.text('State B');
}
else{
inner.$button.text('State A');
}
});
self.getState= function(){
return inner.$button.text();
};
return self;
};
MyApp.Mediator = (function(){
var self = {}, widgetA, widgetB;
widgetA = new MyApp.WidgetA();
widgetB = new MyApp.WidgetB();
$(widgetA).bind('StateNeeded', function(event, callback){
//Mediator askes Widget for state
var state = widgetB.getState();
callback(state);
});
return self;
})();
})(MyApp);
</script>
</body>
</html>