观察者和订阅发布者的简单实现和区别对比

39 阅读2分钟

image.png

[发布订阅和观察模式都是一种行为型设计模式,用来实现对象之间的一对多的通知机制。它们的区别主要有以下几点 1 2 3 4 5 6 7

  • 观察者模式中,观察者和被观察者是直接交互的,观察者需要订阅被观察者的事件,并且被观察者需要维护一个观察者列表,当事件发生时,被观察者会遍历这个列表并通知每个观察者。这样就导致了观察者和被观察者之间存在一定的耦合性,如果被观察者发生变化,可能会影响到所有的观察者。
  • 发布订阅模式中,发布者和订阅者之间没有直接联系,而是通过一个第三方的调度中心来进行消息的传递。发布者只需要将消息发送给调度中心,订阅者只需要从调度中心订阅感兴趣的消息,当消息到达时,调度中心会负责将消息分发给对应的订阅者。这样就实现了发布者和订阅者之间的解耦,它们不需要知道对方的存在。
  • 观察者模式更多地用于单个应用内部的对象间通信,而发布订阅模式更多地用于跨应用或跨系统的消息传递

简易发布订阅模式


function EventEmitter() {
  this._events = {};
}
EventEmitter.prototype.on = function (evetName, fn) {
//订阅
  this._events[evetName] = this._events[evetName] || [];
  this._events[evetName].push(fn);
};
EventEmitter.prototype.emit = function (evetName, args) {
//触发发布
  this._events[evetName].forEach((fn) => {
    fn(args);
  });
};
EventEmitter.prototype.off = function (evetName, fn) {
//解除订阅
  this._events[evetName] = this._events[evetName].filter((item) => {
    return item != fn && item.fn != fn;
  });
};
EventEmitter.prototype.once = function (evetName, fn) {
//只订阅一次,触发就解除订阅
  let once = (...args) => {
    fn(args);
    this.off(evetName, once);
  };
  once.fn = fn;
  this.on(evetName, once);
};
const eventEmitter1 = new EventEmitter();
const handle1 = (name) => {
  console.log("hello" + name);
};
const handle2 = (name) => {
  console.log("goodbye" + name);
};
const handle3 = (name) => {
  console.log("juest one time:" + name);
};

eventEmitter1.on("handle1", handle1);
eventEmitter1.on("handle1", handle2);
eventEmitter1.emit("handle1", "joker");
console.log('---------------');
eventEmitter1.once("handle1", handle3);
eventEmitter1.off("handle1", handle2);
eventEmitter1.emit("handle1", "joker");
console.log('---------------');
eventEmitter1.emit("handle1", "joker");

image.png

观察者有耦合关系,但是订阅者不关心接受信息的人拿信息去做什么,两者是解耦的

简易观察者模式模式

class Subject {
    deps: Array<Observer>
    state: Number
    constructor() {
        this.deps = []
        this.state = 0
    }
    attach(obs: Observer): void {
        this.deps.push(obs)
    }
    setState(state: number) {
        this.state = state
        this.notifyAll()
    }
    notifyAll(): void {
        this.deps.forEach((item: Observer) => {
            item.run(this.state)
        })
    }
}
abstract class Observer {
    subject: Subject
    constructor(subject: Subject) {
        this.subject = subject
        console.log(this);
        
        this.subject.attach(this)
    }
    abstract run(data: Number | String): void
}
class BinaryObserver extends Observer {
    constructor(subject: Subject) {
        super(subject)
    }
    run() {
        console.log('this is BinaryObserver');
    }
}
class ArrayObserver extends Observer {
    constructor(subject: Subject) {
        super(subject)
    }
    run() {
        console.log('this is ArrayObserver');
    }
}
const subject = new Subject()
const obj1 = new BinaryObserver(subject)
const obj2 = new ArrayObserver(subject)
subject.setState(2)

image.png