Subscription-publish patterns for design patterns manual

Official definition:

Subscription-publish pattern: Defines a one-to-many dependency between objects so that all dependent objects can be notified when the state of one object changes.

My thoughts:

One undesirable side effect of splitting a system into a series of cooperating classes is the need to maintain consistency between corresponding objects, which can make maintenance, extension, and reuse difficult. Subscription publishing is used when changes to one object require changes to other objects, and it does not know exactly how many objects need to be changed. When an abstract model has two aspects, one of which depends on the other, the subscription publishing pattern encapsulates the two in separate objects, allowing them to change and reuse independently of each other. What the subscription publishing model does is decouple. Make both sides of the coupling dependent on abstraction, rather than concrete, so that changes on either side do not affect changes on the other.


What is the subscription-publish model?

Subscription-publish pattern: Defines a one-to-many dependency between objects so that all dependent objects can be notified when the state of one object changes.

Those of you who are familiar with event mechanics or functional programming will appreciate the benefits of “temporal decoupling” and “spatial decoupling” brought about by the subscription-publish model. This design pattern can be implemented elegantly with the help of the concepts of closures and callbacks in functional programming.


Subscription-publish vs. observer

The subscription-publish pattern is similar in concept to the observer pattern, but in the subscription-publish pattern, there is an additional layer of middleware between subscribers and publishers: an abstract information scheduling center.

But there’s no need to delve too deeply into the difference, because the classic book Head First Design Patterns says publish + subscribe = Observer. The core idea is state changes and notifications. On this basis, according to the language characteristics, can be implemented.

The difference between
  • In the publisher/subscriber pattern, the component is completely separate from the observer pattern. In the observer pattern, subject and observer are loosely coupled.
  • The observer pattern is implemented primarily in a synchronous manner, where a topic invokes the appropriate methods of all its observers when some event occurs. The publisher/subscriber pattern is primarily implemented asynchronously (using message queues).
  • The publisher/subscriber pattern is more like a cross-application pattern. The publisher and subscriber can reside in two different applications. Each of them communicates through a message broker or message queue.

Code implementation

JS generally uses the event model instead of the traditional publish-subscribe model. When the prototype chain of any object is referred to as an Event, the object can be bound to a custom Event and its corresponding callback function.

Const Event = {clientList: {}, // Bind Event listener (key, fn) {if (! this.clientList[key]) { this.clientList[key] = []; } this.clientList[key].push(fn); return true; } / / trigger corresponding event trigger () {const key = Array. The prototype. The shift. The apply (the arguments), FNS = this. ClientList [key]; if (! fns || fns.length === 0) { return false; } for (let fn of fns) { fn.apply(null, arguments); } return true; }, // remove related events remove(key, fn) {let FNS = this.clientList[key]; // If there is no previous binding event // or no specified event to remove // returns if (! fns || ! fn) { return false; } // remove the specified event function for (let l = fn. Length -1; l >= 0; l--) { let _fn = fns[l]; if (_fn === fn) { fns.splice(l, 1); } } return true; }}; Const installEvent = obj => {for (let key in Event) {obj[key] = Event[key]; }}; let salesOffices = {}; installEvent(salesOffices); SalesOffices. Listen (" event01", (fn1 = price => {console.log(" price is", price, "at event01"); })); salesOffices.listen( "event02", (fn2 = price => { console.log("Price is", price, "at event02"); })); salesOffices.trigger("event01", 1000); salesOffices.trigger("event02", 2000); salesOffices.remove("event01", fn1); Console. log(salesOffices. Trigger ("event01", 1000));Copy the code