JavaScript: Design Pattern-Observer Pattern

Source: Internet
Author: User

JavaScript: Design Pattern-Observer Pattern
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 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 ={}, // The subUid of the array stored by the callback function =-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:

    // Come, subscribe to a pubsub. subscribe ('example1', function (topics, data) {console. log (topics +: + data) ;}); // publish the 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 testsubmodules = pubsub. subscribe ('example1', function (topics, data) {console. log (topics +: + data) ;}); // publish the 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); // publish it again to verify whether the pubsub information can be output. 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:

    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 increase his salary! ') ;}; O. subscribe (f1); o. subscribe (f2); o. update (Tom is back !) // Unsubscribe (f1); // verify 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 = {// subscribe to 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: function (what) {for (var I = 0; I <this. subscribers. length; I ++) {if (typeof this. subscribers [I] === 'function') {this. subscribers [I] (what) ;}}, // 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:

    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 ):

    Var tom = {read: function (what) {console. log ('Tom saw the following information: '+ what) }}; var mm = {show: function (what) {console. log ('Mm saw the following information: '+ what) }}; // subscribe to blogger. addSubscriber (tom. read); blogger. addSubscriber (mm. show); blogger. recommend (123); // call publish // unsubscribe blogger. removeSubscriber (mm. show); blogger. recommend (456); // call publish // subscribe user of another object. 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 ($) {    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 callback function handle (e, a, B, c) {// 'E' is the event object and you do not need to pay attention to the 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 (unsubscribe uses the/some/topic name instead of the callback function, different from version 1's 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.

     

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.