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:
- Supports Simple broadcast communication to automatically notify all subscribed objects.
- After a page is loaded, the target object is easily dynamically associated with the observer, increasing flexibility.
- The abstract coupling relationship between the target object and the observer can be expanded and reused independently.
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.
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 MIn 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:
//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:
// 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 prototype features to implement an observer model,CodeAs 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:
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 A;
};
}
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:
// Common Code
VaR Observer = {
// Subscription
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]);
}
}
},
// Release
Publish: Function (What ){
For ( VaR I = 0; I < This . Subscribers. length; I ++ ){
If ( Typeof This . Subscribers [I] === 'function '){
This . Subscribers [I] (what );
}
}
},
// Enable object O with 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:
VaRBlogger = {
Recommend:Function(ID ){
VaRMSG = 'dudu recommended post: '+ ID;
This. Publish (MSG );
}
};
VaRUser = {
Vote:Function(ID ){
VaRMSG = '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 ):
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)
}
};
// Subscription
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:
(Function($ ){
VaRO =$ ({});
$. 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:
// 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 );
};
// Subscription
$. Subscribe ("/Some/topic", handle );
// Release
$. Publish ("/Some/topic", ["A", "B", "C"]); // Output ABC
$. Unsubscribe ("/Some/topic", handle );// Unsubscribe
// Subscription
$. 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.
Reference address:
Https://github.com/shichuan/javascript-patterns/blob/master/design-patterns/observer.html
Http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjavascript
Https://gist.github.com/661855
Transferred from: Uncle Tom