观察者模式&发布订阅模式

644 阅读2分钟

本文作为学习记录(有理解错误的地方欢迎大佬们指出)

观察者模式

观察者模式解决什么问题

在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化,也就是说当对象间存在一对多关系时,在这样的情况下就可以使用观察者模式。当一个对象被修改时,则会自动通知它的依赖对象。

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

/**
 * 观察者模式代码实现
 */
 
class SubJect {
	constructor() {
		this.observer = [];
	}

	addOberser(oberser) {
		this.observer.push(oberser);
	}

	cancelOberser(oberser) {
		this.observer = this.observer.filter(item => item !== oberser);
	}

	notify() {
		this.observer.forEach(i => i.update());
	}
}

class Oberver {
	constructor(name) {
		this.name = name;
	}

	update() {
		console.log(`my name updateing ${this.name}`)
	}
}

let test = new SubJect();

let person1 = new Oberver('person: 囡囡子');
let person2 = new Oberver('person: 崽崽子');

test.addOberser(person1);
test.addOberser(person2);
test.cancelOberser(person1);

test.notify();

优点: 观察者模式满足“开-闭原则”,主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。

缺点: 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用(如果上面Oberver也是一个观察目标),可能导致系统崩溃。观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

发布订阅模式

发布订阅模式解决了什么问题

这个模式用来作为一个调度中心或者商品中心,一个把发布者和订阅者架接在一起的代理。发布者是当完成某些过程或者发布一个产品的时候触发事件的对象,订阅者是希望当发布者发布的时候希望被通知的对象。

主要解决:让发布者发布消息,订阅者接受消息而不是寻找一种方式把两个系统连接在一起。

/**
 * 发布订阅模式实现
 */
 
class Schedule {
	constructor() {
		this.products = {};
	}

	subscriberProduct(name, cb) {
		if (!this.products[name]) this.products[name] = [];
		this.products[name].push(cb);
	}

	publishProduct() {
		let args = arguments;
		const name = Array.prototype.shift.call(args);
		const cbs = this.products[name];
		if (!cbs || cbs.length === 0) return;
		cbs.forEach(cb => cb.apply(this, args))
	}

	cancelSubscriberProduct(name) {
		delete this.products[name];
	}

}

let appleStore = new Schedule();

appleStore.subscriberProduct('iphone', (time) => {
	console.log(`手机店关注了新款iphone发布时间为 ${time}`)
});

appleStore.subscriberProduct('iphone', (time) => {
	console.log(`个人关注了新款iphone发布时间为 ${time}`)
});

appleStore.subscriberProduct('macbookPro', (sales) => {
	console.log(`macbookPro正在促销 促销价为 ¥${sales}`)
});

appleStore.cancelSubscriberProduct('macbookPro')

appleStore.publishProduct('iphone', '2020-10-10');
appleStore.publishProduct('macbookPro', '10000');

优点: 对象之间的解耦,在异步编程里可以更送耦的方式组织代码结构,更具灵活性,不需要关系中间过程是如何实现的只需要发布者和订阅者共同遵守一份协议。

缺点: 与观察者模式一样如果有循环依赖同样可能会造成系统崩溃,其次创建订阅者本身要消耗一定的时间和内存,本身products对象也是一个缓存列表。