Observer模式(觀察者設計模式)
Observer 設計模式?
在Observer模式中, 當觀察物件的狀態發生變化時,會通知給觀察者 。Observer模式適用於根據物件狀態進行相應處理的場景。
-
Observer 並非主動觀察,而是被動觀察,實際可以又稱之為 釋出-訂閱者 模式
-
MVC
Model、View、Controller,並且Model裡面的操作不依賴於具體形式的內部模型,通常情況下:
一個Model對應多個View,這裡也是使用Observer設計模式最多的地方
-
java中觀察者介面
在package java.util;下存在了Observer介面,按照二類定義模式,允許傳遞物件,以及附帶引數
void update(Observable o, Object arg);
- 使用注意:java.util.observer介面和java.util.observable類並不好用。理由很簡單,傳遞給java.util.observer介面的Subject角色必須是java.util.observable型別(或者它的子型別)的。但Java只能單一繼承,也就說如果Subject角色已經是某個類的子類了,那麼它將無法繼承java.util.observable類。(單個使用還是可以的)
理清職責
- 實現功能:根據不同的觀察者顯示字串的方式也不一樣!
|名字=======》》》說明
|Observer || 表示觀察者的介面
|NumberGenerator || 表示生成數值的物件的抽象類
|RandomNumberGenerator || 生成隨機數的類
|Digitobserver || 表示以數字形式顯示數值的類
|Graphobserver || 表示以簡單的圖示形式顯示數值的類
|Main || 測試程式行為的類
-
Observer呼叫順序問題:
當在Observer存在多個需要通知的方法時,方法一多,容易出現混亂,所以你這裡使用template設計模式將在Observer定義的使用順序,提前安排好,
那麼子類去實現就行了。出現更改呼叫順序的時機,只需要去Observer中檢視。
- 可替換性原則:
-
利用抽象類與介面從具體的類中抽象出方法
2.將例項作為引數傳遞到類中,或者在類的欄位中儲存例項時,不要使用具體的型別,而是使用抽象型別介面作為引數傳遞。
- 相關設計模式
◆Mediator模式
在Mediator模式中,有時會使用Observer 模式來實現Mediator角色與Colleague角色之間的通訊。
就“傳送狀態變化通知”這一點而言,Mediator模式與Observer模式是類似的。不過,兩種模式中,通知的目的和視角不同。
在Mediator模式中,雖然也會發送通知,不過那不過是為了對Colleague角色進行仲裁而已。
而在Observer模式中,將Subject角色的狀態變化通知給Observer角色的目的則主要是為了使Subject角色和Observer角色同步。
UML
類圖:
Code
- Observer 、NumberGenerator
public interface Observer { /** * 通知concreateObserver * @param numberGenerator */ void update(NumberGenerator numberGenerator); } public abstract class NumberGenerator { private List<Observer> observers=new ArrayList<>(); /** * 增加觀察者 * @param observer */ public void addObserver(Observer observer){observers.add(observer);}; /** * 移除觀察者 * @param observer */ public void deleteObserver(Observer observer){observers.remove(observer);}; /** * 通知所有的觀察者 */ protected void notifyObservers(){ Iterator<Observer> it = observers.iterator(); while (it.hasNext()){ Observer next = it.next(); next.update(this); } } /** * 獲取數值 */ public abstract int getNumber(); /** * 生成數值 */ public abstract void excute(); }
- Graphobserver 、Digitobserver 兩個觀察者
public class Digitobserver implements Observer { @Override public void update(NumberGenerator numberGenerator) { System.out.println(this.getClass().getName()+":"+numberGenerator.getNumber()); try { Thread.sleep(100); }catch (InterruptedException e){ e.printStackTrace(); } } } public class Graphobserver implements Observer { @Override public void update(NumberGenerator numberGenerator) { System.out.println(this.getClass().getName()+":"); for (int i = 0; i < numberGenerator.getNumber(); i++) { System.out.print("*"); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }
- RandomNumberGenerator
public class RandomNumberGenerator extends NumberGenerator{ private Random random=new Random(); private int number; @Override public int getNumber() { return number; } /** * 生成一次數值,通知一次觀察者 */ @Override public void excute() { for (int i = 0; i < 20; i++) { number=random.nextInt(50); notifyObservers(); } } }
- MainT
public class MainT { public static void main(String[] args) { NumberGenerator generator = new RandomNumberGenerator(); // 觀察者 Digitobserver digitobserver = new Digitobserver(); Graphobserver graphobserver = new Graphobserver(); generator.addObserver(digitobserver); generator.addObserver(graphobserver); generator.excute(); } }