在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
什么是发布订阅模式?能手写实现一下吗?它和观察者模式有区别吗?... 1 场景引入我们先来看这么一个场景: 假设现在有一个社交平台,平台上有一个大V叫 Nami很牛,多才多艺,目前她有2个技能:会写歌、会拍视频 她会把这些作品发布到平台上。关注她的粉丝就会接收到这些内容 现在他已经有3个粉丝了,分别是:Luffy、Zoro、Sanji 每次只要Nami一发布作品,3个粉丝的账号上收到的消息就会更新 现在用代码来表示: const luffy = { update: function (songs, videos) { console.log(songs, videos); }, }; const zoro = { update: function (songs, videos) { console.log(songs, videos); }, }; const sanji = { update: function (songs, videos) { console.log(songs, videos); }, }; const nami = { // 只要Nami的作品一更新,这个方法就会被调用 workUpdate: function () { // 获取作品 const songs = this.getSongs(); const videos = this.getVideos(); // 账号更新 luffy.update(songs, videos); zoro.update(songs, videos); sanji.update(songs, videos); }, getSongs: function () { return "mp3"; }, getVideos: function () { return "mp4"; }, }; 现在问题来了
发现问题没有? 粉丝对象和大V对象之间的耦合度太高,导致两者很难各自扩展 2 代码优化2.1 解决增加粉丝问题先来解决上述第1个问题,使得增加粉丝的时候不用再修改 首先,我们将“大V”抽象成一个类Star,用数组 class Star { constructor() { this.fans = []; } addFans(fan) { this.fans.push(fan) } workUpdate() { const songs = this.getSongs(); const videos = this.getVideos(); this.fans.forEach((item) => item.update(songs, videos)); } getSongs() { return "MP3"; } getVideos() { return "MP4"; } } 接着,将“粉丝”也抽象成一个类Fan,我们在创建粉丝对象的时候传入“大V”对象,调用该大V的 class Fan { constructor(name, star) { this.name = name this.star = star this.star.addFans(this) } update(songs, videos) { console.log(songs, videos); } } 现在我们添加粉丝就不必再更改代码了 const nami = new Star() const luffy = new Fan("luffy", nami); const zoro = new Fan("zoro", nami); const sanji = new Fan("sanji", nami); const robin = new Fan("robin", nami); nami.workUpdate() 2.2 解决添加作品问题我们新增一个 class Star { constructor() { this.fans = []; this.works = []; } addFans(fan) { this.fans.push(fan); } setWorks(work) { this.works.push(work); // 添加作品后,调用更新方法 this.workUpdate(); } getWorks() { return this.works; } workUpdate() { this.fans.forEach((item) => item.update()); } } 对类Fan进行相应修改: class Fan { constructor(name, star) { this.name = name this.star = star this.star.addFans(this) } update() { console.log(`${this.name}:${this.star.getWorks()}`) } } 现在大V添加作品就不必再更改代码了: const nami = new Star(); nami.setWorks('song') nami.setWorks('video') nami.setWorks('novel') const luffy = new Fan("luffy", nami); const zoro = new Fan("zoro", nami); const sanji = new Fan("sanji", nami); nami.workUpdate(); 3 观察者模式可以看到,在上述例子中,一个 事实上,这就是观察者模式
我们将2.2中的代码进行进一步的抽象: 将“粉丝”看作观察者(
具体代码如下: // 被观察者:主题 class Subject { constructor() { this.observerList = []; // 代表主题状态 this.state = 0; } addObserver(observer) { this.observerList.push(observer); } // 更改主题状态 setState(state) { this.state = state; // 状态改变后,通知所有观察者 this.notify(); } getState() { return this.state; } notify() { this.observerList.forEach((observer) => observer.update()); } } // 观察者 class Observer { constructor(name, subject) { this.name = name; this.subject = subject; this.subject.addObserver(this); } update() { console.log(`${this.name}:${this.subject.state}`); } } 4 经纪人登场由于大V业务繁忙,所以他们需要经纪人来维持艺人与粉丝的联系 经纪人的工作包括:
抽象成一个类,如下: class Manager { constructor() { this.fans = []; this.works = []; } addFans(fan) { this.fans.push(fan); } setWorks(work) { this.works.push(work); // 添加作品后,调用更新方法 this.workUpdate(); } getWorks() { return this.works; } workUpdate() { this.fans.forEach((item) => item.update()); } } 嗯?这段代码貌似在哪儿见过? 没错,和2.2的Star类一模一样,只不过把类名改了改。 那这么做有意义吗? 事实上,代码一模一样是因为在2.2的Star类中我们只写了有关发布(即发布作品)和订阅(即维护粉丝列表)的功能;而Star类本身可能不止这个工作,比如创作内容。 现在我们将 另一方面,粉丝 于是Star和Fan的代码如下: class Star { constructor() {} // 创作 create(manager) { // 将创作的new work交给经纪人 manager.setWorks("new work"); } } class Fan { constructor(name, manager) { this.name = name; this.manager = manager; this.manager.addFans(this); } update() { console.log(`${this.name}:${this.manager.getWorks()}`); } } 5 发布订阅模式前面我们用了经纪人来负责发布和订阅的工作,而不让 这就是发布订阅模式 我们将4中的Manager进行进一步的抽象: 将“粉丝”看作订阅者( 具体代码如下: // 发布订阅调度中心 class Broker { constructor() { this.subscribers = []; // 代表主题状态 this.state = 0; } // 订阅 subscribe(subscriber) { this.subscribers.push(subscriber); } // 更改主题状态 setState(state) { this.state = state; // 状态改变后,发布 this.publish(); } getState() { return this.state; } // 发布 publish() { this.subscribers.forEach((subscriber) => subscriber.update()); } } // 发布者 class Publisher { constructor() {} changeState(broker, state) { broker.setState(state); } } class Subscriber { constructor(name, broker) { this.name = name; this.broker = broker; this.broker.subscribe(this); } update() { console.log(`${this.name}:${this.broker.getState()}`); } } 来运行一下看看效果: // 创建调度中心 const broker = new Broker() // 创建发布者 const publisher = new Publisher() // 创建订阅者 const subscribe1 = new Subscriber('s1', broker) const subscribe2 = new Subscriber('s2', broker) const subscribe3 = new Subscriber('s3', broker) // 发布者改变状态并通知调度中心,调度中心就会通知各个订阅者 publisher.changeState(broker, 1) 6 观察者模式和发布订阅模式的对比
|
请发表评论