Head First設計模式之觀察者模式

早就對“設計模式”這個詞有所耳聞,最早是在大一看《大話數據結構》這本書的背后看到這個系列還有個《大話設計模式》,我當時還以為這個“設計模式”恐怕是給設計師看的吧,當然這是望文生義了。其實設計模式官方解釋是:

設計模式(Design Pattern)是一套被反復使用、多數人知曉的、經過分類的、代碼設計經驗的總結。

其實我認為就是大家總結的寫代碼的套路吧。

觀察者模式

觀察者模式從名字上來看大概就是一種通知與被通知的關系,其實代碼思想也與其差不多,其核心思想就是有一個或N個觀察者(Observer)和一個(或N個)被觀察者(Observable 或 Subject),觀察者以訂閱方式來觀察被觀察者,當被觀察者接到更新時(程序員控制或代碼自動發出)將通知所有觀察者來接受更新的內容。這就有點像一群學生(Observer,觀察者)和書店老板(Observable 或 Subject,被觀察者),當書店每次新進漫畫雜志時,就會通知所有學生去購買。下面就看看如何用代碼來實現這個事件。

所需接口

我們需要一共三個接口來定義Observer和Observable的行為,為別是 Observer 和 Observable 本身,還有DisplayElement來定義Observer的輸出動作。

public interface Observable
{
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
public interface Observer
{
    void update(String book);
}
public interface DisplayElement
{
    void display();
}

接口定義的方法都很好理解,Observable 接口定義了將 Observer 對象加入或刪除自己的隊列里,還有通知隊列里的 Observer。當書店有新書進入時,就會調用 Observer 的 update 方法。

實現接口

我們需要的類只有兩個,當然就是 BookStore 對象和 Student 對象。

public class BookStore implements Observable
{
    private List<Observer> observers;
    private String newBook;
    public BookStore()
    {
        this.observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer)
    {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer)
    {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers()
    {
        if(newBook!=null)
        {
            for (Observer observer : observers)
            {
                observer.update(newBook);
            }
        }
        newBook=null;
    }

    public void newBookComing(String bookName)
    {
        newBook = bookName;
        notifyObservers();
    }

}
public class Student implements DisplayElement , Observer
{
    private String name;
    private List<String> hasBooks;
    private Observable observable;
    public Student(String name,Observable observable)
    {
        this.name = name;
        this.hasBooks = new ArrayList<>();
        this.observable = observable;
        observable.registerObserver(this);
    }

    @Override
    public void update(String book)
    {
        hasBooks.add(book);
        System.out.print(name+"買到了書<"+book+">   ");
        display();
    }

    @Override
    public void display()
    {
        System.out.println(name+"有書->"+hasBooks.toString());
    }
}

可以看到 BookStore 就是實現了很簡單的 Observable 類的三個接口,其中在 notifyObservers 方法中依次調用隊列中的 Observer 對象的 update 方法,BookStore 在 newBookComing 方法中設置新書的名字和調用 notifyObservers 方法。而 Student 則是在 update 方法中將新書加入自己已有的書籍集合中,最后調用 display 方法打印目前所有的書名。值得注意的是 Student 對象是把被觀察者在自己的構造函數里傳入,然后在構造函數里調用被觀察者(這里就是 BookStore)的 registerObserver 方法將自己加入到隊列中去。我認為當然也可以不這么做,也可以 bookStore.registerObserver(xiaohua); 來加入BookStore的隊列,RxJava就是這么做的。

測試

現在建立一個測試類來跑一跑我們的代碼:

public class Main
{
    public static void main(String[] args)
    {
        BookStore bookStore = new BookStore();
        Student xiaoming = new Student("小明", bookStore);
        Student xiaohua = new Student("小華", bookStore);
        Student xiaozhang = new Student("小張", bookStore);
        bookStore.newBookComing("知音漫客");
        bookStore.newBookComing("故事會");
        bookStore.newBookComing("看天下");
    }
}

那么我們僅僅用了這么幾行代碼就跑出了我們想要的結果:

小明買到了書<知音漫客> 小明有書->[知音漫客]

小華買到了書<知音漫客> 小華有書->[知音漫客]

小張買到了書<知音漫客> 小張有書->[知音漫客]

小明買到了書<故事會> 小明有書->[知音漫客, 故事會]
小華買到了書<故事會> 小華有書->[知音漫客, 故事會]
小張買到了書<故事會> 小張有書->[知音漫客, 故事會]
小明買到了書<看天下> 小明有書->[知音漫客, 故事會, 看天下]
小華買到了書<看天下> 小華有書->[知音漫客, 故事會, 看天下]
小張買到了書<看天下> 小張有書->[知音漫客, 故事會, 看天下]

總結

如果以后有新書來的話,只需要一行代碼 bookStore.newBookComing("知音漫客"); 就可以完成所有的通知動作了。觀察者模式將變化的部分與固定的部分分開從而實現了松耦合,這就是觀察者模式的威力。java 在自己的 util 包里也內置了一個觀察者模式,他的類名與我寫的代碼的類名是一樣的,有所不同的是內置的 Observable 是一個類而不是一個接口,因為他幫我們把 registerObserver ,removeObserver ,notifyObservers 都實現了,其余的使用方法都大同小異。

Github 源代碼地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容