前提:
在翻閱資料的時候,有人把觀察者(Observer)模式等同於發佈(Publish)/訂閱(Subscribe)模式,也有人認爲這兩種模式仍是存在差別,而我認爲確實是存在差別的,本質上的區別是調度的地方不一樣。可是由於後者是前者發展變異而來,故而列到一篇博客中html
觀察者模式
比較概念的解釋是,目標和觀察者是基類,目標提供維護觀察者的一系列方法,觀察者提供更新接口。具體觀察者和具體目標繼承各自的基類,而後具體觀察者把本身註冊到具體目標裏,在具體目標發生變化時候,調度觀察者的更新方法。前端
由於前端語言紛繁複雜,下邊我分別舉出es五、es六、ts版本java
ts版本程序員
/*** * 抽象被觀察者接口 * 聲明瞭添加、刪除、通知觀察者方法 */ public interface Observerable { registerObserver(o:Observer); removeObserver(o:Observer):; notifyObserver(); } /*** * 抽象觀察者 * 定義了一個update()方法,當被觀察者調用notifyObservers()方法時,觀察者的update()方法會被回調。 */ public interface Observer { update( message:string); } /** * 被觀察者,也就是微信公衆號服務 * 實現了Observerable接口,對Observerable接口的三個方法進行了具體實現 */ public class WechatServer implements Observerable { private list:Observer[]; private message:string; constructor(){ this.list = []; } public registerObserver(o: Observer) { this.list.push(o) } public removeObserver(o: Observer) { for (var i=0; i < this.list.length; i++){ if (this.list[i] === o){ this.list.splice(i, 1); break; } } } public notifyObserver() { for(let i = 0; i < this.list.length; i++) { let oserver = this.list[i]; oserver.update(this.message); } } public setInfomation(s:string) { this.message = s; console.log(`微信服務更新消息:${s}`); //消息更新,通知全部觀察者 this.notifyObserver(); } } /** * 觀察者 */ public class User implements Observer { private name:string; private message:string; constructor(name:string) { this.name = name; } public update(message:string) { this.message = message; this.read(); } public read() { console.log(`${this.name}收到推送消息:${this.message}`); } } /** * 咱們來測試 */ let server = new WechatServer(); let userZhang = new User("張三"); let userLi = new User("李四"); let userWang = new User("王五"); server.registerObserver(userZhang); server.registerObserver(userLi); server.registerObserver(userWang); server.setInfomation("PHP是世界上最好用的語言!"); console.log("-----用戶張三看到消息後頗爲震驚,果斷取消訂閱,這時公衆號又推送了一條消息,此時用戶ZhangSan已經收不到消息,其餘用戶仍是正常能收到推送消息----------------"); server.removeObserver(userZhang); server.setInfomation("JAVA是世界上最好用的語言!"); /** * 總結:這個是ts去寫的,由於用js寫,我以爲理解起來很費勁,哪怕是es2018!編譯後可能就是你想要的版本吧 * 這個模式是典型的觀察者模式,而非變異後的發佈-訂閱模式,二者有關聯,可是並不同 * 其實前邊兩個接口是能夠不用定義的,可是接口就是用來作規範的,之後可能不僅有微信服務,還有新聞訂閱、小程序訂閱、iphoneXR訂購等等 * 這個模式是鬆偶合的。改變主題或觀察者中的一方,另外一方不會受到影像 * 參考自java設計模式:https://www.cnblogs.com/luohanguo/p/7825656.html */
es5版本
寫完以後,忽然發現,這尼瑪不就是ts編譯後的代碼嘛,那兩個抽象類的做用僅僅用在編譯階段,編譯後的代碼並不存在相關接口代碼,哦!原來ts是這麼個機制es6
/** * 被觀察者,也就是微信公衆號服務 */ var WechatServer = (function () { function WechatServer() { this.list = []; } WechatServer.prototype.registerObserver = function (o) { this.list.push(o); }; WechatServer.prototype.removeObserver = function (o) { for (var i = 0; i < this.list.length; i++) { if (this.list[i] === o) { this.list.splice(i, 1); break; } } }; WechatServer.prototype.notifyObserver = function () { for (var i = 0; i < this.list.length; i++) { var oserver = this.list[i]; oserver.update(this.message); } }; WechatServer.prototype.setInfomation = function (s) { this.message = s; console.log(`微信服務更新消息:${s}`); //消息更新,通知全部觀察者 this.notifyObserver(); }; return WechatServer; }()); /** * 觀察者 */ var User = (function () { function User(name) { this.name = name; } User.prototype.update = function (message) { this.message = message; this.read(); }; User.prototype.read = function () { console.log(`${this.name}收到推送消息:${this.message}`); }; return User; }()); /** * 咱們來測試 */ let server = new WechatServer(); let userZhang = new User("張三"); let userLi = new User("李四"); let userWang = new User("王五"); server.registerObserver(userZhang); server.registerObserver(userLi); server.registerObserver(userWang); server.setInfomation("PHP是世界上最好用的語言!"); console.log("-----用戶張三看到消息後頗爲震驚,果斷取消訂閱,這時公衆號又推送了一條消息,此時用戶ZhangSan已經收不到消息,其餘用戶仍是正常能收到推送消息----------------"); server.removeObserver(userZhang); server.setInfomation("JAVA是世界上最好用的語言!");
es6版本
經過這個能夠了解到,由於目前包括es2018還沒有實現接口、抽象功能,故而沒法定義觀察者約束性接口,而後還知道了,es6只是語法糖,相似於ts同樣,建立類,其實本質就是es5 混合繼承知識點:屬性用構造,公共函數放在原型對象上,這樣全部實例在內存共享一個方法,節省內存,說遠了,哈哈不說了,貼代碼面試
/** * 被觀察者,也就是微信公衆號服務 */ class WechatServer{ constructor(){ this.list = []; } registerObserver(o) { this.list.push(o); }; removeObserver(o){ for (var i = 0; i < this.list.length; i++) { if (this.list[i] === o) { this.list.splice(i, 1); break; } } } notifyObserver() { for (var i = 0; i < this.list.length; i++) { var oserver = this.list[i]; oserver.update(this.message); } } setInfomation(s){ this.message = s; console.log(`微信服務更新消息:${s}`); //消息更新,通知全部觀察者 this.notifyObserver(); } } /** * 觀察者 */ class User{ constructor(name) { this.name = name; } update(message) { this.message = message; this.read(); }; read (){ console.log(`${this.name}收到推送消息:${this.message}`); }; }; /** * 咱們來測試 */ let server = new WechatServer(); let userZhang = new User("張三"); let userLi = new User("李四"); let userWang = new User("王五"); server.registerObserver(userZhang); server.registerObserver(userLi); server.registerObserver(userWang); server.setInfomation("PHP是世界上最好用的語言!"); console.log("-----用戶張三看到消息後頗爲震驚,果斷取消訂閱,這時公衆號又推送了一條消息,此時用戶ZhangSan已經收不到消息,其餘用戶仍是正常能收到推送消息----------------"); server.removeObserver(userZhang); server.setInfomation("JAVA是世界上最好用的語言!");
最後再想嗶嗶兩句:
ts和es6都是語法糖,因此面試的人會問你編譯以後會是啥樣,挺操dan的,由於java歷來不會問我編譯後的字節碼是什麼樣
ts跟es6比,就拿這個來講,可使用接口來約束觀察者,防止程序員亂寫,能夠用數據類型來約束各類參數和返回值,防止亂傳,等到了運行再報錯,代碼我都寫了幾千行了,誰tm找獲得啊。大致來講ts語法約束性較強,是強數據類型語言了,不少錯編譯階段就會報錯!小程序