Design mode-publish-subscriber mode

Source: Internet
Author: User

1. Publish-Subscriber design mode

Defined

Defines a one-to-many dependency between objects, and all objects that depend on it will be notified when the state of an object changes

The difference between the observer pattern and the publish subscription pattern

The Observer pattern is scheduled by a specific target (publisher/observer), and the Publish/subscribe pattern is dispatched by a separate dispatch center, so there is a dependency between the Subscriber and the publisher of the Observer pattern, and the Publish/subscribe mode does not; The publish-subscribe pattern is further decoupled from the observer pattern, A pattern that is used extensively in practice

* * Viewer Mode * *
1. Definition/Resolution
The target and the observer are the base classes, the target provides a series of methods to maintain the observer, and the Observer provides an update interface. Specific observers and targets inherit their own base classes, and then the specific observer registers themselves with the specific target, scheduling the Observer's Update method when the specific target is changed.

2. Schedule Diagram/Flowchart

3. Implementing the Code

Observer list function observerlist () {this.observerlist = [];} ObserverList.prototype.add = function (obj) {return this.observerList.push (obj);};o BserverList.prototype.count = function () {return this.observerlist.length;};o BserverList.prototype.get = function (index) {if (Index >-1 && Index < this.observerList.length) {RET  Urn 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;};o BserverList.prototype.removeAt = function (index) {this.observerList.splice (index, 1);};/ /target 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); }};//Observer function Observer () {this.update = function () {//...};}

4. Observer composition (Java):

    • Abstract Theme role: All references to observer objects are saved in a collection, and each abstract theme role can have any number of observers. Abstract topics provide an interface that can be added and deleted * In addition to the observer role. It is generally implemented with an abstract class and interface.
    • Abstract Observer role: Define an interface for all specific observers and update yourself when you get notifications for a topic.
    • Specific topic role: Notifies all registered observers when the internal state of a specific topic changes. A specific theme role is typically implemented with a subclass.
    • Specific observer role: This role implements the update interfaces required by the abstract observer role in order to reconcile the state of itself with the state of the topic. Typically implemented with a subclass. If necessary, the specific observer role can save a reference to a specific topic role.

5. Class Diagram (Java)

Simplified version:

6. Time series diagram (Java)

7.java Implementation Code

/* Abstract Observer (Observer) */public interface Observer {public void update (String message);    /* Specific observer (CONCREREOBSERVER): Implement abstract interface */public class Weixinuser implements Observer {//user name private String name;    Public Weixinuser (String name) {this.name = name;    } @Override public void update (String message) {SYSTEM.OUT.PRINTLN (name + "-" + message); }}/* Abstract Viewer/target object/subject (Subject) */public interface Subject {/** * ADD subscribers * @param observer */public void att    Ach (Observer Observer);    /** * DELETE subscribers * @param observer */public void Detach (Observer observer); /** * Notifies subscribers of UPDATE messages */public void notify (String message); /* Specific viewer/target object/subject (Subject) */public class Subscriptionsubject implements Subject {//Store subscription to public number of users private List<observ    er> weixinuserlist = new arraylist<observer> ();    @Override public void Attach (Observer Observer) {weixinuserlist.add (Observer); } @Override public void detach (Observer observer) {WEIXINUSERLIST.REMOVE (Observer); } @Override public void notify (String message) {for (Observer observer:weixinuserlist) {Observ        Er.update (message); }}}/* client calls */public class client {public static void main (string[] args) {Subscriptionsubject msubscription        Subject=new Subscriptionsubject ();        Create User Weixinuser user1=new weixinuser ("Yolanda Maple");        Weixinuser user2=new Weixinuser ("The Moon Eyebrow Son");        Weixinuser user3=new weixinuser ("Purple Xuan");        Subscribe to the public number Msubscriptionsubject.attach (user1);        Msubscriptionsubject.attach (User2);        Msubscriptionsubject.attach (USER3);    The public number update sends a message to subscribers of the subscription msubscriptionsubject.notify ("Liu Wangshu's Column updated"); }}

* * Publish/Subscribe mode * *
1. Definition/Resolution
The subscriber registers the event that he wants to subscribe to the dispatch center, when the event triggers, the Publisher publishes the event to the Dispatch center (incidentally), and the dispatch center centrally dispatches the subscriber to the dispatch center's processing code.

2. Schedule Diagram/Flowchart

3. Implementing the Code

1.javascript Classic var pubsub = {};(function (myObject) {//Storage for topics, can be broadcast//or listened T    o var topics = {};    An topic identifier var subuid =-1; Publish or broadcast events of interest//with a specific topic name and arguments//such as the data to pass a        Long myobject.publish = function (topic, args) {if (!topics[topic]) {return false; } var subscribers = Topics[topic], len = subscribers?        subscribers.length:0;        while (len--) {subscribers[len].func (topic, args);    } return this;    }; Subscribe to events of interest//with a specific topic name and A/callback function, to be executed//WH En the topic/event is observed myobject.subscribe = function (topic, func) {if (!topics[topic]) {T        Opics[topic] = [];        } var token = (++subuid). toString (); Topics[topic].push ({token:token, func:func});    return token;    }; Unsubscribe from a specific//topic, based in a tokenized reference//to the subscription MYOBJECT.UNSUBSCRI is = 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 this; };} (PubSub));                 /2.javascript General Edition var event = {clientlist: [],//subscriber list listen:function (key, FN) {//Publisher listening and subscribing to events                 if (!this.clientlist[key]) {this.clientlist[key] = [];                } this.clientlist[key].push (FN)//subscribed message added into cache list}, Trigger:function () {//Trigger subscription Event var key = Array.prototype.shift.call (arguments),//(1);                FNS = this.clientlist[key];                if (!fns | | fns.length = = = 0) {//if no corresponding message is bound to return false; } for (var i = 0, fn; fn = fns[i++];)        {fn.apply (this, arguments);//(2)///arguments is the parameter on the trigger when}},                Remove:function (Key, FN) {//unsubscribe var FNS = this.clientlist[key];                if (!FNS) {//if the message corresponding to the key is not subscribed by the person, it returns false directly; if (!FN) {///if no specific callback function is passed, all subscriptions that need to cancel the key corresponding message Fns && (fns.length = 0                 );                                 }else{for (var l = fns.length-1; l >=0; l--) {//Reverse traversal of subscription callback function list                                var _fn = fns[L];                                if (_fn = = = fn) {Fns.splice (L, 1);    }                        }            }}}//This function can dynamically install the publish-subscribe function for all objects: var installevent = function (obj) {for (var i in event) {         obj[i] = event[i]; }};

4. Example:

var login = {}installEvent(login) //  实例化发布-订阅对象 $.ajax( ‘http:// xxx.com?login‘, function(data){ // 登录成功         login.trigger( ‘loginSucc‘, data); // 发布登录成功的消息 data});  var header = (function(){ // header 模块         login.listen( ‘loginSucc‘, function( data){        header.setAvatar( data.avatar );        });         return {                setAvatar: function( data ){                        // 具体操作代码                        console.log( ‘设置 header 模块的头像‘ );                }         }})(); var nav = (function(){ // nav 模块        login.listen( ‘loginSucc‘, function( data ){                监听到登录成功事件后回调操作(具体见return中)                nav.setAvatar( data.avatar );        });         return {                setAvatar: function( avatar ){                         console.log( ‘设置 nav 模块的头像‘ );                }         }})();

5. Enhanced version

The Event object adds the following features 1, provides the ability to create namespaces 2, can be published first, and then subscribes to ******** var Event = (function () {var global = this,     Event, _default = ' default '; Event = function () {var _listen, _trigger, _remove, _slice = A                 Rray.prototype.slice, _shift = Array.prototype.shift, _unshift = Array.prototype.unshift, Namespacecache = {}, _create, find, each = function (ary, FN                    ) {VAR ret;                        for (var i = 0, L = ary.length; i < L; i++) {var n = ary[i];                     ret = Fn.call (n, I, n);                 } return ret;                };                     _listen = function (key, FN, cache) {if (!cache[key]) {cache[key] = [];     } cache[key].push (FN);           };                            _remove = function (key, cache, fn) {if (cache[key]) {if (FN) { for (var i = cache[key].length; I >= 0; i--) {if (cache[key][i] = =                             = fn) {cache[key].splice (i, 1)}                     }} else {cache[key] = []}                }                }; _trigger = function () {var cache = _shift.call (arguments), key = _sh                                Ift.call (arguments), args = arguments, _self = this,                                                 RET, stack = cache[key];                               if (!stack | |!stack.length) { Return                        } return each (stack, function () {return this.apply (_self, args);                });                };                        _create = function (namespace) {var namespace = namespace | | _default;                                        var cache = {}, offlinestack = [], ret = { Listen:function (Key, FN, last) {_listen (key, FN,                                                Cache);                                                 if (offlinestack = = = null) {return;                                                        } if (last = = = ' last ') {                                                 Offlinestack.length && Offlinestack.pop () (); }else{each (offlinestack, function () {                                                         This ();                                                });                                         } offlinestack = null;                                                 }, One:function (Key, FN, last) {                                                 _remove (key, cache);                                        This.listen (Key, FN, last); }, Remove:function (Key, FN) {_rem                                        Ove (key, Cache, FN); }, Trigger:function () {var fn, args , _self = this;                                                 _unshift.call (arguments, cache);                                                args = arguments;                                                 fn = function () {return _trigger.apply (_self, args);                                                };                                                if (offlinestack) {return Offlinestack.push (FN);                                         } return fn ();                        }                                }; Return namespace?                (namespacecache[namespace] namespacecache[namespace]: namespacecache[namespace] = ret): ret;             };                Return {create: _create, One:function (KEY,FN, last) {                 var event = this.create ();                        Event.one (Key,fn,last); }, Remove:function (KEY,FN) {var event = this.create (); Event.remo                        ve (KEY,FN);                                 }, Listen:function (Key, FN, last) {var event = this.create ();                        Event.listen (Key, FN, last);                                }, Trigger:function () {var event = this.create ();                         Event.trigger.apply (this, arguments);         }                };        }(); return Event; })();

Note: In Java, the Subscriber object itself is typically referred to as a reference to the incoming Publisher object, and the Subscriber object needs to provide a method called update, which is called by the Publisher object at the appropriate time. In JavaScript, we replace the traditional publish-subscribe pattern with the form of a registered callback function.

Usage Scenarios

Event callbacks for DOM events in front-end JS
Implementation of the front-end framework vue bidirectional data Binding DefineProperty + Publish-subscriber mode, etc.

Design mode-publish-subscriber mode

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.