《一天一模式》— 觀察者模式

1、觀察者模式的概念

觀察者模式(又被稱爲發佈-訂閱(Publish/Subscribe)模式,屬於行爲型模式的一種,它定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態變化時,會通知全部的觀察者對象,使他們可以自動更新本身。 java

2、何時使用觀察者模式

當一個對象被修改,或者發生某些變化時,須要自動通知依賴它的一些對象,則可使用觀察者模式。編程

例如:當汽車熄火時,須要更新汽車的定位、發送熄火的通知、生成本次的行程,就可使用觀察者模式,這個例子中發生變化的位置是熄火,那麼發生熄火須要通知依賴它的一些對象,就是定位、通知和行程。spa

下面來看看,如何用Java語言實現觀察者模式。設計

3、怎麼使用觀察者模式

3.1 不適用觀察者模式的弊端

用上面說的業務場景爲例,若是不使用觀察者模式來實現,能夠看下面的僞代碼:code

public class EngineOffEvent() {

    public void engineOff() {
        Location localtion = new Localtion();
        Notification notification = new Notification();
        Trip trip = new Trip();

        localtion.update();
        notification.notify();
        trip.createTrip();
    }
}

這種作法有以下兩個主要弊端:server

  • 耦合度高:能夠看到EngineOffEvent類耦合了全部其餘的業務類,形成維護困難;
  • 擴展性差:當須要在熄火時作新業務時,須要修改engineOff方法內的代碼,違反了開閉原則;
  • 靈活度低:不能控制通知的對象個數;

3.2 如何用觀察者模式解決問題

根據上面的需求,用觀察者模式進行設計,下面看看類圖和代碼:對象

代碼以下:blog

/**
 * 觀察者接口。
 * */
public interface Observer {
    /**
     * 當氣象監測數據改變時,主題會把這些狀態值看成方法的參數,傳送給觀察者。
     * */
    void update(String data);
}

public class LocaltionObserver implements Observer{
    public void update(String data) {
        System.out.println(data + ":更新位置。");
    }
}

public class NotificationObserver implements Observer{
    public void update(String data) {
        System.out.println(data + ":發送通知。");
    }
}

public class TripObserver implements Observer {
    public void update(String data) {
        System.out.println(data + ":生成行程。");
    }
}

/**
 * 主題接口。
 * */
public interface Subject {
    /**
     * registerObserver和removeObserver方法都須要一個觀察者做爲變量,該觀察者是用來註冊或被刪除的。
     * */
    void registerObserver(Observer ob);

    void removeObserver(Observer ob);

    /**
     * 當主題的狀態改變時,這個方法會被調用,已通知全部的觀察者。
     * */
    void notifyObservers(String data);

}

// 熄火事件
public class EngineOffEvent implements Subject {

    // 觀察者對象集合
    private List<Observer> observers;

    public EngineOffEvent() {
        observers = new ArrayList<Observer>();
    }

    // 註冊觀察者
    public void registerObserver(Observer ob) {
        observers.add(ob);
    }

    // 移除觀察者
    public void removeObserver(Observer ob) {
        int index = observers.indexOf(ob);
        if (index >= 0)
            observers.remove(index);
    }

    // 發生變化進行通知
    public void notifyObservers(String data) {
        // 通知所有觀察者
        for (Observer ob : observers) {
            ob.update(data);
        }
    }

}

// 使用
public class Client {

    public static void main(String[] args) {
        Subject subject = new EngineOffEvent();
        subject.registerObserver(new LocaltionObserver());
        subject.registerObserver(new NotificationObserver());
        subject.registerObserver(new TripObserver());
        subject.notifyObservers("京A88888熄火");
    }

}

//京A88888熄火:更新位置。
//京A88888熄火:發送通知。
//京A88888熄火:生成行程。

觀察者模式主要分爲兩部分:繼承

  • Subject,主題,是發生變化的那個對象,例子中是熄火事件;
  • Observer,觀察者,是發生變化後須要通知的多個對象,例子中是通知、位置和行程;

在使用時,能夠動態添加或者刪除觀察者,靈活配置。接口

3.3 觀察者模式的好處

  • 耦合度低:解除了3.1小節中,EngineOffEvent類與其餘的業務類的耦合;
  • 擴展性高:當須要在熄火時作新業務時,建立一個新對象實現Observer,而後註冊到Subject便可;
  • 靈活度高:能夠隨意添加或移除Observer;

3.4 其餘能夠注意的地方

Java內置了觀察者模式:

  • java.util.Observable(類)

  • java.util.Observer(接口)

可使用內置的觀察者,可是其中Observable對應的是上面例子中的Subject,他是一個Class而不是Interface,若是使用內置的接口,則須要把寶貴繼承機會用掉,若你的類已經使用了繼承關係,則沒法使用。

4、總結

上面的觀察者模式,從代碼上來講,就是面相接口編程,在Subject中有一個List<Observer>,在發生變化後,循環調用List中的對象的方法,確保都通知到,而且能夠對List進行添加和刪除。

從業務上來講,當發生某個事件後,須要批量通知許多個對象。則可使用這個模式。

以上就是我對觀察者模式的一些理解,有不足之處請你們指出,謝謝。

相關文章
相關標籤/搜索