This article mainly introduces multiple implementation version instances of the observer mode of Javascript design mode. This article provides three implementation version codes and Jquery implementation versions. For more information, see
Introduction
The Observer Mode is also called the Publish/Subscribe mode. it defines a one-to-many relationship, allowing multiple observer objects to listen to a topic object at the same time, when the status of the topic object changes, all observer objects are notified so that they can automatically update themselves.
Benefits of using the observer mode:
1. supports simple broadcast communication to automatically notify all subscribed objects.
2. after a page is loaded, the target object is easily dynamically associated with the Observer, increasing flexibility.
3. the abstract coupling relationship between the target object and the observer can be expanded and reused separately.
Body (version 1)
In JS, the implementation of the observer mode is implemented through callback. We first define a pubsub object, which contains three methods: subscription, unsubscription, and release.
The code is as follows:
Var pubsub = {};
(Function (q ){
Var topics ={}, // array stored by the callback function
SubUid =-1;
// Release method
Q. publish = function (topic, args ){
If (! Topics [topic]) {
Return false;
}
SetTimeout (function (){
Var subscribers = topics [topic],
Len = subscribers? Subscribers. length: 0;
While (len --){
Subscribers [len]. func (topic, args );
}
}, 0 );
Return true;
};
// Subscription method
Q. subscribe = function (topic, func ){
If (! Topics [topic]) {
Topics [topic] = [];
}
Var token = (++ subUid). toString ();
Topics [topic]. push ({
Token: token,
Func: func
});
Return token;
};
// Unsubscribe method
Q. unsubscribe = function (token ){
For (var m in topics ){
If (topics [m]) {
For (var I = 0, j = topics [m]. length; I <j; I ++ ){
If (topics [m] [I]. token = token ){
Topics [m]. splice (I, 1 );
Return token;
}
}
}
}
Return false;
};
} (Pubsub ));
The usage is as follows:
The code is as follows:
// Come, subscribe to
Pubsub. subscribe ('example1', function (topics, data ){
Console. log (topics + ":" + data );
});
// Release notification
Pubsub. publish ('example1', 'Hello world! ');
Pubsub. publish ('example1', ['test', 'A', 'B', 'C']);
Pubsub. publish ('example1', [{'color': 'blue'}, {'text': 'Hello'}]);
How is it? Is it easy to use? However, there is a problem with this method, that is, there is no way to unsubscribe to the subscription. to unsubscribe to the subscription, you must specify the unsubscribe name. so let's use another version:
The code is as follows:
// Assign the subscription value to a variable to unsubscribe.
Var testsubscribe = pubsub. subscribe ('example1', function (topics, data ){
Console. log (topics + ":" + data );
});
// Release notification
Pubsub. publish ('example1', 'Hello world! ');
Pubsub. publish ('example1', ['test', 'A', 'B', 'C']);
Pubsub. publish ('example1', [{'color': 'blue'}, {'text': 'Hello'}]);
// Unsubscribe
SetTimeout (function (){
Pubsub. unsubscribe (testsubscribe );
}, 0 );
// Release it again to verify whether information can be output.
Pubsub. publish ('example1', 'Hello again! (This will fail )');
Version 2
We can also use the features of the prototype to implement an Observer Mode. the code is as follows:
The code is as follows:
Function Observer (){
This. fns = [];
}
Observer. prototype = {
Subscribe: function (fn ){
This. fns. push (fn );
},
Unsubscribe: function (fn ){
This. fns = this. fns. filter (
Function (el ){
If (el! = Fn ){
Return el;
}
}
);
},
Update: function (o, thisObj ){
Var scope = thisObj | window;
This. fns. forEach (
Function (el ){
El. call (scope, o );
}
);
}
};
// Test
Var o = new Observer;
Var f1 = function (data ){
Console. log ('robbin: '+ data +', hurry up! ');
};
Var f2 = function (data ){
Console. log ('Randall: '+ data +', ask him to pay more! ');
};
O. subscribe (f1 );
O. subscribe (f2 );
O. update ("Tom is back! ")
// Unsubscribe f1
O. unsubscribe (f1 );
// Verify again
O. update ("Tom is back! ");
If you cannot find the filter or forEach function, it may be because your browser is not new enough and does not support the new standard function. you can define it as follows:
The code is as follows:
If (! Array. prototype. forEach ){
Array. prototype. forEach = function (fn, thisObj ){
Var scope = thisObj | window;
For (var I = 0, j = this. length; I <j; ++ I ){
Fn. call (scope, this [I], I, this );
}
};
}
If (! Array. prototype. filter ){
Array. prototype. filter = function (fn, thisObj ){
Var scope = thisObj | window;
Var a = [];
For (var I = 0, j = this. length; I <j; ++ I ){
If (! Fn. call (scope, this [I], I, this )){
Continue;
}
A. push (this [I]);
}
Return;
};
}
Version 3
To enable multiple objects to have the Observer publish and subscribe function, we can define a common function and apply the function to the object that requires the Observer function. the code is as follows:
The code is as follows:
// Common code
Var observer = {
// Subscribe
AddSubscriber: function (callback ){
This. subscribers [this. subscribers. length] = callback;
},
// Unsubscribe
RemoveSubscriber: function (callback ){
For (var I = 0; I <this. subscribers. length; I ++ ){
If (this. subscribers [I] === callback ){
Delete (this. subscribers [I]);
}
}
},
// Publish
Publish: function (what ){
For (var I = 0; I <this. subscribers. length; I ++ ){
If (typeof this. subscribers [I] === 'function '){
This. subscribers [I] (what );
}
}
},
// The object o has the Observer function
Make: function (o ){
For (var I in this ){
O [I] = this [I];
O. subscribers = [];
}
}
};
Subscribe to the two objects blogger and user, and use the observer. make method to make the two objects have the observer function. the code is as follows:
The code is as follows:
Var blogger = {
Recommend: function (id ){
Var msg = 'dudu recommended post: '+ id;
This. publish (msg );
}
};
Var user = {
Vote: function (id ){
Var msg = 'someone voted! ID = '+ id;
This. publish (msg );
}
};
Observer. make (blogger );
Observer. make (user );
It is easy to use. subscribe to different callback functions so that they can be registered to different observer objects (or multiple observer objects can be registered at the same time ):
The code is as follows:
Var tom = {
Read: function (what ){
Console. log ('Tom sees the following information: '+ what)
}
};
Var mm = {
Show: function (what ){
Console. log ('Mm sees the following information: '+ what)
}
};
// Subscribe
Blogger. addSubscriber (tom. read );
Blogger. addSubscriber (mm. show );
Blogger. recommend (123); // call release
// Unsubscribe
Blogger. removeSubscriber (mm. show );
Blogger. recommend (456); // call release
// Subscription of another object
User. addSubscriber (mm. show );
User. vote (789); // call release
JQuery version
Based on the on/off function added in jQuery1.7, we can also define the observer of jQuery:
The code is as follows:
(Function ($ ){
Var o =$ ({});
$. Subscribe = function (){
O. on. apply (o, arguments );
};
$. Unsubscribe = function (){
O. off. apply (o, arguments );
};
$. Publish = function (){
O. trigger. apply (o, arguments );
};
} (JQuery ));
The call method is simpler than the preceding three versions:
The code is as follows:
// Callback function
Function handle (e, a, B, c ){
// 'E' is the event object and does not need to be followed.
Console. 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 (the unsubscribe uses the/some/topic name instead of the callback function. it is different from the version 1 example.
$. Unsubscribe ("/some/topic ");
We can see that his subscription and unsubscription use the string name instead of the callback function name, so even if the input is an anonymous function, we can unsubscribe it.
Summary
When an object needs to change other objects at the same time and does not know how many objects need to be changed, the observer mode should be considered.
In general, the work done by the Observer Mode is decoupling, so that both sides of the coupling depend on abstraction, rather than on specifics. So that their changes do not affect the changes on the other side.