Introduced
The observer pattern, also called the Publish subscription pattern (Publish/subscribe), defines a one-to-many relationship that allows multiple observer objects to listen to a Subject object at the same time, notifying all observer objects when the state of the subject changes, so that they can automatically update themselves.
Benefits of using the Observer pattern:
- Supports simple broadcast communication and automatically notifies all subscribed objects.
- After a page is loaded the target object is easily associated with a dynamic association with the observer, adding flexibility.
- The abstract coupling relationship between the target object and the observer can be extended and reused independently.
Body (Version one)
JS in the implementation of the observer pattern is implemented through callbacks, we will first define a PubSub object, which contains 3 methods: Subscribe, unsubscribe, publish.
varPubSub = {};(function(q) {varTopics = {},//array to which the callback function is storedSubuid =-1; //Publish MethodQ.publish =function(topic, args) {if(!Topics[topic]) { return false; } setTimeout (function () { varSubscribers =Topics[topic], Len= subscribers? subscribers.length:0; while(len--) {subscribers[len].func (topic, args); } }, 0); return true; }; //Subscription MethodQ.subscribe =function(topic, func) {if(!Topics[topic]) {Topics[topic]= []; } varToken = (+ +subuid). toString (); Topics[topic].push ({token:token, func:func}); returntoken; }; //Unsubscribe MethodQ.unsubscribe =function(token) { for(varMinchtopics) { if(Topics[m]) { for(vari = 0, j = topics[m].length; I < J; i++) { if(Topics[m][i].token = = =token) {Topics[m].splice (i,1); returntoken; } } } } return false; };} (PubSub));
Use the following methods:
// , subscribe to a function (topics, data) { + ":" +// Post notification pubsub.publish (' example1 ', ' Hello world! ' );p ubsub.publish (' example1 ', [' Test ', ' a ', ' B ', ' C '));p ubsub.publish (' example1 ', [{' Color ': ' Blue '}, {' text ': ' Hello '}]);
What do you think? Isn't it cool to use? However, there is a problem with this approach, that is, there is no way to unsubscribe from the subscription, you must specify the name of the unsubscribe, so we have another version:
//assign a subscription to a variable to unsubscribevarTestsubscription = Pubsub.subscribe (' example1 ',function(topics, data) {Console.log (Topics+ ": " +( data);}); //Publish NotificationsPubsub.publish (' example1 ', ' Hello world! ');p Ubsub.publish (' Example1 ', [' Test ', ' a ', ' B ', ' C ']);p ubsub.publish (' Example1 ', [{' Color ': ' Blue '}, {' text ': ' Hello '}]); //UnsubscribeSetTimeout (function() {pubsub.unsubscribe (testsubscription);},0); //Publish again to verify that you can also output informationPubsub.publish (' example1 ', ' Hello again! (This would fail) ');
Version Two
We can also use the characteristics of the prototype to implement an observer pattern, the code is as follows:
functionObserver () { This. FNS = [];} Observer.prototype={subscribe:function(FN) { This. Fns.push (FN); }, Unsubscribe:function(FN) { This. FNS = This. Fns.filter (function(EL) {if(El!==fn) { returnel; } } ); }, Update:function(o, thisobj) {varScope = Thisobj | |window; This. Fns.foreach (function(EL) {El.call (scope, O); } ); }}; //Testvaro =NewObserver;varF1 =function(data) {Console.log (' Robbin: ' + data + ', hurry up and work! ‘);}; varF2 =function(data) {Console.log (' Randall: ' + data + ', get him some pay! ‘);}; O.subscribe (F1); O.subscribe (F2); O.update ("Tom's Back!" ") //Unsubscribe F1O.unsubscribe (F1);//again to verifyO.update ("Tom's Back! ");
If you are prompted not to find the filter or the Foreach function, it may be that your browser is not new enough to temporarily support the new standard function, and you can define it yourself in the following ways:
if(!Array.prototype.forEach) {Array.prototype.forEach=function(FN, thisobj) {varScope = Thisobj | |window; for(vari = 0, j = This. length; I < J; ++i) {Fn.call (scope, This[i], I, This); } };}if(!Array.prototype.filter) {Array.prototype.filter=function(FN, thisobj) {varScope = Thisobj | |window; varA = []; for(vari = 0, j = This. length; I < J; ++i) {if(!fn.call (Scope, This[i], I, This)) { Continue; } A.push ( This[i]); } returnA; };}
Version Three
If you want multiple objects to have the ability of an observer to publish a subscription, we can define a common function and then apply the function to the object that needs the observer's functionality, with the following code:
//General CodevarObserver = { //SubscribeAddsubscriber:function(callback) { This. subscribers[ This. subscribers.length] =callback; }, //UnsubscribeRemovesubscriber:function(callback) { for(vari = 0; I < This. subscribers.length; i++) { if( This. subscribers[i] = = =callback) { Delete( This. Subscribers[i]); } } }, //PublishPublishfunction(what) { for(vari = 0; I < This. subscribers.length; i++) { if(typeof This. subscribers[i] = = = ' function ') { This. Subscribers[i] (what); } } }, //the object o has observer functionalityMakefunction(o) { for(varIinch This) {O[i]= This[i]; O.subscribers= []; } }};
Then subscribe to 2 objects Blogger and user, using the Observer.make method to have these 2 objects with the Observer function, the code is as follows:
var blogger = { function (ID) { var msg = ' Dudu Recommended posts: ' + id;
this. Publish (msg); var user = { function (ID) { var msg = ' Someone voted!id= ' +< c19> ID; This . Publish (msg);} ; Observer.make (blogger); Observer.make (user);
The use of the method is relatively simple, subscribe to different callback functions, so that can be registered to different observer objects (also can be registered to multiple observer objects):
varTom ={read:function(what) {Console.log (Tom saw the following message: ' +What )}}; varMM ={show:function(what) {Console.log (' mm saw the following message: ' +What )}};//SubscribeBlogger.addsubscriber (Tom.read); Blogger.addsubscriber (mm.show); Blogger.recommend (123);//Invoke Publish //UnsubscribeBlogger.removesubscriber (mm.show); Blogger.recommend (456);//Invoke Publish //a subscription to another objectUser.addsubscriber (mm.show); User.vote (789);//Invoke Publish
jquery version
Based on the new on/off feature of version jQuery1.7, we can also define the jquery version of the viewer:
(function ($) { var o = $ ({}); function () { o.on.apply (o, arguments); }; function () { o.off.apply (o, arguments); }; function () { o.trigger.apply (o, arguments); };} (JQuery));
Calling a method is simpler than the previous 3 versions:
//callback functionfunctionhandle (E, A, B, c) {//' E ' is an event object that does not require attentionConsole.log (A + B +c);}; //Subscribe$.subscribe ("/some/topic", handle);//Publish$.publish ("/some/topic", ["a", "B", "C"]);//OUTPUT ABC$.unsubscribe ("/some/topic", handle);//Unsubscribe //Subscribe$.subscribe ("/some/topic",function(E, A, B, c) {Console.log (a+ B +c);}); $.publish ("/some/topic", ["a", "B", "C"]);//OUTPUT ABC //Unsubscribe (unsubscribe using the/some/topic name, not the callback function Oh, not the same as the example of version one$.unsubscribe ("/some/topic");
As you can see, his subscription and unsubscribe use the string name instead of the callback function name, so even if the anonymous function is passed in, we can unsubscribe.
Summarize
The observer's use situation is that when an object's change needs to change other objects at the same time, and it doesn't know how many objects need to be changed, you should consider using the observer pattern.
In general, the work of the observer pattern is decoupling, allowing both sides of the coupling to rely on abstraction, rather than relying on specifics. So that their changes will not affect the change on the other side.
This article from http://www.cnblogs.com/TomXu/archive/2012/03/02/2355128.html
The observer pattern for JavaScript design patterns