我试图弄清楚在某种情况下应该遵循哪种模式。我有一个网络应用程序,它由几个主要的小部件组成,这些小部件以某种方式相互交互。小部件遵循模块模式。
让代码说话:
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 可以使用react的情况。但我有一种情况,A 独立启动某件事,但需要检查 B 的某个状态才能继续。
当我努力实现可维护性时,我正在寻找摆脱这个 hell 的方法。
我首先想到的是中介者模式。
但是,我的代码仍然是这样的:
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 不直接通信,而是通过中介器间接通信。
但是,我仍然觉得我做错了,必须有更好的方法来实现部件之间的解耦。
编辑
让我总结一下到目前为止的情况!
总的来说,我确实喜欢分离 View 的 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>
最佳答案
您应该查看 Addy Osmani Patterns For Large-Scale JavaScript Application Architecture 发表的关于大型 JS 应用程序的精彩文章这是代码示例 Essential js design patterns
关于javascript - 在这种情况下,比调解器模式更好的方法来解耦小部件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4275070/