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("第三本書", "三毛");
}
}
輸出結果:
我是讀者讀者一很高興收到了大毛*第一本書
我是讀者讀者二很高興收到了大毛*第一本書
我是讀者讀者一很高興收到了二毛*第二本書
我是讀者讀者二很高興收到了二毛*第二本書
我是讀者讀者一很高興收到了三毛*第三本書
我是讀者讀者二很高興收到了三毛*第三本書
以上。
如有不對請指出。