I'm working through the design pattern example for the Observer Pattern in Addy Osmani's book, "JavaScript Design Patterns". My question is why is it important that there are so many levels of abstraction in his implementation of the pattern?
For instance, in his example, just to add an observer ('push' an observer to an array), this involves:
- using the native
push()
method. - creating a
ObjectList.add()
method. - inheriting/extending the
ObjectList
object with theSubject
object. - creating the
Subject.addObserver()
method which to be used as an interface, but which uses theObjectList.add
method under the hood. - extending the
Subject.addObserver()
method for new objects. - Implementing it by calling the
addObserver()
method on the newly extended object.
Here's the code example for the design pattern in its entirety:
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(){
// ...
};
}
And here's the implementation/usage:
HTML
<button id="addNewObserver">Add New Observer checkbox</button>
<input id="mainCheckbox" type="checkbox"/>
<div id="observersContainer"></div>
Script
// 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 );
}
Now I compared his implementation with other implementations of the same pattern (books and blogs). And it seems that Addy adds a ton more abstraction than other implementors of the observer pattern. The question is, why? Couldn't this be done more simple? Does this achieve a greater degree of decoupling? If so, how exactly is that? Doesn't the design pattern itself create a decoupling?
Aucun commentaire:
Enregistrer un commentaire