JavaScript:为什么在Addy';什么是观察者模式?
我正在研究Addy Osmani的书《JavaScript设计模式》中Observer模式的设计模式示例。我的问题是,为什么在他的模式实现中有如此多的抽象层次很重要 例如,在他的示例中,只需添加一个观察者(“推”一个观察者到一个数组),这包括:JavaScript:为什么在Addy';什么是观察者模式?,javascript,design-patterns,observer-pattern,observers,Javascript,Design Patterns,Observer Pattern,Observers,我正在研究Addy Osmani的书《JavaScript设计模式》中Observer模式的设计模式示例。我的问题是,为什么在他的模式实现中有如此多的抽象层次很重要 例如,在他的示例中,只需添加一个观察者(“推”一个观察者到一个数组),这包括: 使用本机push()方法 创建ObjectList.add()方法 使用主题对象继承/扩展对象列表对象 创建Subject.addObserver()方法,该方法将用作接口,但在引擎盖下使用ObjectList.add方法 为新对象扩展Subject.
- 使用本机
方法push()
- 创建
方法ObjectList.add()
- 使用
对象继承/扩展主题
对象对象列表
- 创建
方法,该方法将用作接口,但在引擎盖下使用Subject.addObserver()
方法ObjectList.add
- 为新对象扩展
方法Subject.addObserver()
- 通过对新扩展的对象调用
方法来实现它addObserver()
function ObserverList(){
this.observerList = [];
}
ObserverList.prototype.add = function( obj ){
return this.observerList.push( obj );
};
ObserverList.prototype.count = function(){
return this.observerList.length;
};
ObserverList.prototype.get = function( index ){
if( index > -1 && index < this.observerList.length ){
return this.observerList[ index ];
}
};
ObserverList.prototype.indexOf = function( obj, startIndex ){
var i = startIndex;
while( i < this.observerList.length ){
if( this.observerList[i] === obj ){
return i;
}
i++;
}
return -1;
};
ObserverList.prototype.removeAt = function( index ){
this.observerList.splice( index, 1 );
};
function Subject(){
this.observers = new ObserverList();
}
Subject.prototype.addObserver = function( observer ){
this.observers.add( observer );
};
Subject.prototype.removeObserver = function( observer ){
this.observers.removeAt( this.observers.indexOf( observer, 0 ) );
};
Subject.prototype.notify = function( context ){
var observerCount = this.observers.count();
for(var i=0; i < observerCount; i++){
this.observers.get(i).update( context );
}
};
// The Observer
function Observer(){
this.update = function(){
// ...
};
}
现在,我将他的实现与相同模式的其他实现(书籍和博客)进行了比较。看起来Addy比observer模式的其他实现者添加了更多的抽象。问题是,为什么?难道不能更简单地通过继承ObserverList
对象来实现吗?这是否能像Addy那样实现更大程度的解耦?如果是,具体情况如何?设计模式本身不是创造了一种解耦吗?似乎主题
对象带来了很多不必要的代码
难道不能更简单地通过从
观察者列表对象
对。通过继承,不会重新实现所有的ObserverList
方法。代码更少,测试更少,文档更少
这是否实现了更大程度的解耦,就像Addy那样
是吗
是的,这是因为主题
对象的接口根本不依赖于观察者列表
接口(因为Subject
重新实现了它自己与这些方法的接口,所以它的接口与observer列表
接口是分离的。这有它的优点和缺点。重新实现一个接口应该有很好的理由,因为它大部分只是一堆额外的代码,没有添加任何实际有用的功能。
如果是,具体情况如何
通过重新实现您自己的版本,将实际接口隐藏到observer列表
,从而使这两个接口解耦。对底层observer列表
接口的更改可以被主题
接口隐藏。而主题
实现仍然依赖并耦合到observer列表
接口,主题
接口本身独立于观察者列表
接口。但是,也有很多理由不这样做,所以不要认为每个接口都应该与其他接口分离。这将是一场灾难
似乎Subject对象带来了很多不必要的代码
是的
当您想要使用来自另一个对象的功能,并且想要将该功能的部分或全部公开给您自己对象的客户时,您有许多设计选择
主题中使用公开的观察者进行编码d看起来像这样:
var s=新主题();
s、 observer.add(函数(){
//当主题更改时,将调用此函数
});
observer列表
对象。在第二种情况下,您的对象“有一个”observer列表
对象。在第三种情况下,您的对象“在其实现中隐藏一个”observer列表
对象
每种设计选择都有利弊。没有一种选择总是正确或错误的,因为每种选择都有不同的利弊,哪种选择是最佳的取决于具体情况 选项1)继承的情况通常是当您的对象是基础对象的扩展时,从架构上讲,它被认为是基础对象的更强大版本和/或它可能重写基础对象上的方法。这里的情况并非如此。a
Subject()
对象不是一个功能更强大的observer列表
对象。它是一种使用observer列表
的不同类型的对象
选项2)包含ObserverList的公共实例并允许对象的用户使用该公共实例的情况是,当对象实际上是一种不同类型的对象,但它希望使用另一种类型对象的功能并向其用户公开时。在我看来,这里发生的事情主要是这样的
选项3)的情况是,您不希望对象的接口与任何其他接口之间存在任何接口依赖关系。在这种情况下,您不能公开其他对象的接口来让对象的用户使用这些接口。相反,你有
<button id="addNewObserver">Add New Observer checkbox</button>
<input id="mainCheckbox" type="checkbox"/>
<div id="observersContainer"></div>
// Extend an object with an extension
function extend( extension, obj ){
for ( var key in extension ){
obj[key] = extension[key];
}
}
// References to our DOM elements
var controlCheckbox = document.getElementById( "mainCheckbox" ),
addBtn = document.getElementById( "addNewObserver" ),
container = document.getElementById( "observersContainer" );
// Concrete Subject
// Extend the controlling checkbox with the Subject class
extend( new Subject(), controlCheckbox );
// Clicking the checkbox will trigger notifications to its observers
controlCheckbox.onclick = function(){
controlCheckbox.notify( controlCheckbox.checked );
};
addBtn.onclick = addNewObserver;
// Concrete Observer
function addNewObserver(){
// Create a new checkbox to be added
var check = document.createElement( "input" );
check.type = "checkbox";
// Extend the checkbox with the Observer class
extend( new Observer(), check );
// Override with custom update behaviour
check.update = function( value ){
this.checked = value;
};
// Add the new observer to our list of observers
// for our main subject
controlCheckbox.addObserver( check );
// Append the item to the container
container.appendChild( check );
}