天天看點

設計模式-觀察者模式 釋出/訂閱模式

設計模式-觀察者模式 釋出/訂閱模式

代碼

觀察者接口

public interface IHanFeiZi{ // 當吃早飯時 public void havBreakFast(); // 進行娛樂活動時 public void haveFun(); }           

具體的被觀察者

public class HanFeiZi implements IHanFeiZi{ `// 根據是否在吃飯,作為監控的标準 private boolean isHavingBreakfast = false; // 判斷是否在娛樂 private boolean isHavingFun = false; // 當吃飯的時候 public void haveBreakfast(){ System.out.println("吃飯了"); this.isHavingBreakfast = true; } // 當開始娛樂的時候 public void haveFun(){ System.out.println("開始娛樂"); this.isHavingFun = true; } // 下方位get/set省去 }           

觀察者

public interface ILiSi{ // 發行有人有動靜,進行行動 public void update(String context); }

public class LiSi implements ILiSi{ // 首先他為一個觀察者 public void update(String str){ System.out.println("觀察到某人活動,進行彙報"); this.reportToQinShiHuang(str); // 調用彙報方法 System.out.println("彙報完畢"); } // 進行彙報、 private void reportToQinShiHuang(String reportContext){ System.out.println("進行彙報"); } }           

最後定義中間

class Spy extends Thread{ private HanFeiZi hanFeiZi; private LiSi liSi; private String type; // 通過構造函數注入,顯示将要監控誰 public Spy(HanFeiZi _hanFeiZi, LiSi _liSi, String _type){ this.hanFeiZi = _hanFeiZi; this.liSi = _liSi; this.type = _type; } @Override public void run(){ while(true){ if(this.type.equals("breakfast")){ // 監控是否吃早餐 // 如果在吃飯,則通知 if(this.hanFeiZi.isHavingBreakfast()){ this.liSi.update("在吃飯"); // 重置狀态,繼續監控 this.hanFeiZi.setHavingBreakfast(false); } }else{ // 判斷是否在娛樂 if(this.hanFeiZi.isHavingFun()){ this.liSi.update("在娛樂"); this.hanFeiZi.setHavingFun(false); } } } } }           

場景類

public class Client{ public static void main(String[] args) throws interruptedException { // 定義兩個人 LiSi liSi = new LiSi(); HanFeiZi hanFeiZi = new HanFeiZi(); // 觀察早餐 Spy watchBreakfast = new Spy(hanFeiZi, lisi, "breakfast"); watchBreak.start(); // 啟動線程、https://www.iming.info/2019/01/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F-%E5%8F%91%E5%B8%83-%E8%AE%A2%E9%98%85%E6%A8%A1%E5%BC%8F/ // 繼續檢視都幹什麼 Thread.sleep(1000); hanFeiZi.haveBreakfast(); // 開始吃飯 // 如果娛樂 Thread.sleep(1000); hanFeiZi.haveFun(); // 檢視情況 } }           

修改

由于上面使用了一個死循環,會導緻出現問題。并且由于多線程的緣故,會導緻資料的污染問題,根本無法使用。

修改如下

public class HanFeiZi implements IHanFeiZi{ // 聲明李 private ILiSi lisi = new LiSi(); // 當吃飯的時候 public void hanveBreakfast(){ System.out.println("吃飯開始"); this.liSi.update("吃飯了"); } // 當娛樂的時候 public void haveFun(){ System.out.println("開始娛樂"); this.liSi.update("在娛樂"); } }




最後書寫場景類




public class Client{ public static void main(String[] args){ // 定義出韓 HanFeiZi hanFeiZi = new HanFeiZi(); // 繼續檢視韓在幹什麼 hanFeiZi.haveBreakfast(); // 當其娛樂 hanFeiZi.haveFun(); } }           

繼續改進

如果這樣聚合,如果有一堆人需要監控被觀察者,這樣不行,不能一個監控一個,如果此時要修改其他的監控内容,那麼都要修改,違反開閉原則

開閉原則 對擴充開放,對修改關閉

那麼,将被觀察者的自身活動定義一個接口,被觀察者定義接口,在統一的類HanFeiZi中實作該接口,對于觀察者來說,定義一個觀察者的接口,然後多名觀察者分别實作該類

被觀察者

public interface Observable { // 增加一個觀察者 public void addObserver(Observer observer); // 删除一個觀察者 public void deleteObserver(Observer observer); // 當發生動作的時候,通知觀察者 public void notifyObservers(String context); }

上方是一個統一的觀察者接口,所有的觀察者都能實作這個接口。繼續檢視被觀察者

public class HanFeiZi implements Observalbe, IHanFeiZi{ // 定義數組,用于儲存觀察者 private ArrayList observerList = new ArrayList(); // 增加觀察者 public void addObserver(Observer observer){ this.observerList.add(observer); } // 删除觀察者 public void deleteObserver(Observer observer){ this.observerList.remove(observer); } // 通知所有的觀察者 public void notifyObservers(String context){ for(Observer observer:observerList){ observer.update(context); } } // 當要吃飯了 public void haveBreakfast(){ System.out.println("吃飯"); // 通知觀察者 this.notifyObservers("在吃飯"); } // 開始娛樂 public void haveFun(){ System.out.println("開始娛樂"); this.notifyObservers("在娛樂"); } }

// 書寫觀察者接口 public interface Observer{ // 發現動靜,進行行動 poublic void update(String context); }

// 書寫三個觀察者,隻需要實作觀察者的接口即可 public class LiSi implements Observer{ // 首先要為觀察者 public void update(String str){ System.out.println("開始活動了"); // 彙報 this.reportToQinShiHuang(str); System.out.println("彙報完畢"); } // 彙報 private void reportToQinShiHuang(String reportContext){ System.out.println("進行彙報"); } }           

同理,需要觀察者直接實作接口即可。

public class Client{ public static void main(String[] args){ // 定義三個觀察者 Observer liSi = new LiSi(); Observer wangSi = new WangSi(); Observer liuSi = new LiuSi(); // 定義被觀察的 HanFeiZi hanFeiZi = new HanFeiZi(); // 當三個人觀察韓的時候 hanFeiZi.addObserver(liSi); hanFeiZi.addObserver(wangSi); hanFeiZi.addObserver(liuSi); // 然後檢視在幹什麼 hanFeiZi.haveBreakfast(); } }           

這樣就完成了觀察者模式,當被觀察的發生改變的時候,通知被通過構造方法注入的觀察者,此觀察者儲存在動态數組中,然後當被觀察者發生改變的時候,隻需要使用循環通知儲存在數組中的觀察者即可。

訂閱/釋出模型