設計模式之觀察者模式

  • 定義
  • 類型
  • 類圖
  • 結構
  • 有趣的例子

定義:定義對象間一種一對多的依賴關係,使得當每一個對象改變狀態,則所有依賴於它的對象都會得到通知並自動更新。


類型:行爲類模式


類圖:
這就是觀察者模式類圖


結構:在最基礎的觀察者模式中,包括以下四個角色:

  1. 被觀察者:從類圖中可以看到,類中有一個用來存放觀察者對象的Vector容器(之所以使用Vector而不使用List,是因爲多線程操作時,Vector在是安全的,而List則是不安全的),這個Vector容器是被觀察者類的核心,另外還有三個方法:attach方法是向這個容器中添加觀察者對象;detach方法是從容器中移除觀察者對象;notify方法是依次調用觀察者對象的對應方法。這個角色可以是接口,也可以是抽象類或者具體的類,因爲很多情況下會與其他的模式混用,所以使用抽象類的情況比較多。
  2. 觀察者:觀察者角色一般是一個接口,它只有一個update方法,在被觀察者狀態發生變化時,這個方法就會被觸發調用。
  3. 具體的被觀察者:使用這個角色是爲了便於擴展,可以在此角色中定義具體的業務邏輯。
  4. 具體的觀察者:觀察者接口的具體實現,在這個角色中,將定義被觀察者對象狀態發生變化時所要處理的邏輯。

有趣的例子
1.假設我們有一情景是這樣子的:小孩子在睡覺,醒來後爸爸要給孩子喂東西吃,爺爺要抱小孩子,叔叔要親小孩子。
從情景中我們分析:首先孩子當前的狀態是睡着的,爸爸,爺爺,叔叔都需要觀察小孩子睡醒後才能進行一系列動作。那麼我們很容易想到的就是在實現的時候將小孩子的類封裝到爸爸,爺爺,和叔叔的類中,讓爸爸,爺爺,叔叔去主動觀察小孩子的狀態。這是一種可行的方法,但是此方法需要不斷的去監視小孩子的狀態,導致爸爸,爺爺,叔叔在小孩子睡着的這段時間一直處於狀態,這樣是不是太累了。因此我們想到:將這些觀察者的類封裝到小孩子的類中,讓小孩子主動醒來去通知觀察者來執行相應的操作,這就是我們所要說的觀察者模式。
那麼接下來我們來實現這一情景需求:

Test.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;

class WakenUpEvent {
    private long time;
    private String location;
    private Child source;

    public WakenUpEvent(long time, String location, Child source) {
    super();
    this.time = time;
    this.location = location;
    this.source = source;
    }

    public long getTime() {
    return time;
    }

    public void setTime(long time) {
    this.time = time;
    }

    public String getLocation() {
    return location;
    }

    public void setLocation(String location) {
    this.location = location;
    }

    public Child getSource() {
    return source;
    }

    public void setSource(Child source) {
    this.source = source;
    }

}

class Child implements Runnable {
    private java.util.List<WakenUpListener> wakenUplisteners = new ArrayList<WakenUpListener>();

    public void addWakenUpListener(WakenUpListener l) {
    wakenUplisteners.add(l);
    }

    public void wakeUp() {
    for (int i = 0; i < wakenUplisteners.size(); i++) {
        WakenUpListener l = wakenUplisteners.get(i);
        l.ActionToWakenUp(new WakenUpEvent(System.currentTimeMillis(),
            "bed", this));
    }
    }

    @Override
    public void run() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    this.wakeUp();
    }

}

class Dad implements WakenUpListener {
    public void ActionToWakenUp(WakenUpEvent wakenUpEvent) {
    System.out.println("feed child");
    }
}

class GrandFather implements WakenUpListener {
    public void ActionToWakenUp(WakenUpEvent wakenUpEvent) {
    System.out.println("hug child");
    }
}

interface WakenUpListener {
    public void ActionToWakenUp(WakenUpEvent wakenUpEvent);
}

class PropertyMgr {
    private static Properties properties = new Properties();
    static {
    try {
        properties.load(Test.class.getClassLoader().getResourceAsStream(
            "zhaowanyue/observer.properties"));
    } catch (IOException e) {
        // TODO 自動生成的 catch 塊
        e.printStackTrace();
    }
    }

    public static String getProperty(String key) {
    return properties.getProperty(key);
    }
}

public class Test {
    public static void main(String[] args) throws IOException {
    Child child = new Child();

    String[] observers = PropertyMgr.getProperty("observers").split(",");
    for (String s : observers) {
        try {
        child.addWakenUpListener((WakenUpListener) Class.forName(s)
            .newInstance());
        } catch (InstantiationException | IllegalAccessException
            | ClassNotFoundException e) {

        e.printStackTrace();
        }
    }
    new Thread(child).start();
    }
}
observer.properties
observers=zhaowanyue.Dad,zhaowanyue.GrandFather
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章