1. 程式人生 > >Java設計模式——觀察者模式

Java設計模式——觀察者模式

不知道大家有沒有注意到,生活中有很多時候,發生事件A就會觸發事件B。
還記得上學的時候嗎,每當在課堂上偷偷睡覺的時候,總是會讓同桌在老師過來的時候叫醒自己。這實際上就是同桌充當了“觀察者”,而你充當了“訂閱者”的角色,一旦“老師來了”這件事情發生,你的同桌就會“向你傳送訊息”通知你老師來了。這實際上就是一套“觀察者模式的流程”
觀察者模式定義了物件間的一種一對多依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。
下面以一個小程式來舉例子
假如我們要做一個訂報的小程式,每當報社釋出了一本新書,讀者就會收到新書訊息的通知。
經過一番思考之後,決定這樣設計:定義一個讀者類和報社類。
報社類需要有訂閱讀者的列表,新增或者移除讀者的方法,通知所有訂閱者的方法,更新書本資訊的方法。
讀者類中需要有接受報社傳遞的資訊的方法。
然後寫出瞭如下程式碼:

public class NewsOffice
{
//報社類
    List<Reader> readers;
    public String bookname;
    public String writer;
    public NewsOffice()
    {
        readers = new ArrayList<>();
    }
//註冊讀者
    public void addReader(Reader reader)
    {
       readers.add(reader);
    }
    //移除讀者
    public
void removeReader(Reader reader){ int index=readers.indexOf(reader); if (index>0) { readers.remove(index); } } //通知所有註冊的讀者有新書了 public void notifyAllObserver(){ for(Reader reader:readers){ reader.update(writer+"***"+bookname); } } //設定新書的資訊
public void setInformation(String bookname,String writer){ this.bookname=bookname; this.writer=writer; notifyAllObserver(); } }
public class Reader
{
    String readername;
    String bookinformation;
    public Reader(String readername)
    {
        this.readername = readername;
    }
    public void update(String bookinformation)
    {
        this.bookinformation=bookinformation;
        display();
    }
    private void display()
    {
        System.out.print("我是讀者"+readername+"很高興收到了");
        System.out.println(bookinformation);
    }
}
public class Test
{
    public static void main(String[] a)
    {
        NewsOffice newsOffic = new NewsOffice();
        Reader reader1 = new Reader("讀者一");
        Reader reader2 = new Reader("讀者二");
        newsOffic.addReader(reader1);
        newsOffic.addReader(reader2);
        newsOffic.setInformation("第一本書", "大毛");
        newsOffic.setInformation("第二本書", "二毛");
        newsOffic.setInformation("第三本書", "三毛");
    }
}

輸出結果如下:
我是讀者讀者一很高興收到了大毛*第一本書
我是讀者讀者二很高興收到了大毛*第一本書
我是讀者讀者一很高興收到了二毛*第二本書
我是讀者讀者二很高興收到了二毛*第二本書
我是讀者讀者一很高興收到了三毛*第三本書
我是讀者讀者二很高興收到了三毛*第三本書

這時候看起來似乎結果還是很滿意的,符合系統設計的預期。
但是不知道大家有沒有發現,這是針對實現變成而不是針對介面程式設計。
如果添加了新的型別的讀者,報社需要增加新的程式碼來適配新的讀者。

這時候可以使用今天要介紹的”觀察者模式“來實現
關於觀察者的一切,主題只需要知道觀察者實現了觀察者介面,主題不需要知道觀察者的具體實現。任何時候我們都可以增加或者刪除觀察者,主題不會受到任何影響。
有新的型別的觀察者出現時,主題不需要任何的修改,只要觀察者實現了觀察者介面,即可註冊成為觀察者。主題和觀察者這種鬆耦合的設計,可以應對各種場合。

首先建立觀察者和主題。

public interface Observer
{
//使用Update方法接收傳遞的書本資訊
    public void update(String bookname);

}
public interface Supervisor
{
//增加觀察者
public void addObserver(Observer observer);
//移除觀察者
public void removeObserver(Observer observer);
//通知所有觀察者
public void notifyAllObserver();
}

建立報社類實現主題介面

public class NewsOffice implements Supervisor
{
public List<Observer> observers;
public String bookname;
public String writer;
    public NewsOffice()
{
    observers=new ArrayList<Observer>();

}

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

    @Override
    public void removeObserver(Observer observer)
    {
        int i=observers.indexOf(observer);
        if (i>0)
        {
            observers.remove(i);
        }
    }

    @Override
    public void notifyAllObserver()
    {
    //遍歷所有的觀察者傳送訊息
        for(Observer observer:observers){
            observer.update(writer+"***"+bookname);
        }
    }
    public void setInformation(String bookname,String writer){
    //更新書本的資訊,並且將更新的資訊通過notifyAllObserver傳遞給觀察者
        this.bookname=bookname;
        this.writer=writer;
        notifyAllObserver();
    }
}
public class Reader implements Observer
{
    private String bookinformation;
    private String readername; 

    public Reader(String readername)
    {
        this.readername = readername;
    }

    @Override
    public void update(String bookinformation)
    {
        this.bookinformation = bookinformation;
        display();
    }

    private void display()
    {
        System.out.print("我是讀者"+readername+"很高興收到了");
        System.out.println(bookinformation);
    }
}

測試類如下

public class Test {
    public static void main(String[] a)
    {
        NewsOffice newsOffic = new NewsOffice();
        Reader reader1 = new Reader("讀者一");
        Reader reader2 = new Reader("讀者二");
        newsOffic.addObserver(reader1);
        newsOffic.addObserver(reader2);
        newsOffic.setInformation("第一本書", "大毛");
        newsOffic.setInformation("第二本書", "二毛");
        newsOffic.setInformation("第三本書", "三毛");
    }
}

輸出結果:
我是讀者讀者一很高興收到了大毛*第一本書
我是讀者讀者二很高興收到了大毛*第一本書
我是讀者讀者一很高興收到了二毛*第二本書
我是讀者讀者二很高興收到了二毛*第二本書
我是讀者讀者一很高興收到了三毛*第三本書
我是讀者讀者二很高興收到了三毛*第三本書

以上。
如有不對請指出。