2017年10月5日 星期四

[Design Pattern] 觀察者模式 (Observer Pattern)

「當餐廳更新菜單時,有申請要收到更新通知的會員,就會收到第一手消息」
一對多就是觀察者模式的主軸概念
觀察者模式有二個角色
  1. 主題 - Subject
  2. 觀察者 - Observer
依上面的範例來看
Subject 就是餐廳,Observer 就是會員,餐廳更新的時後就發通知給會員
那我們現在再把這個概念想的完整一點

先從Subject的角度來看,Subject裡要有什麼樣的功能呢?

通知不是發給所有的會員,是只發給「有申請要收到更新通知的會員」
那是不是就要有「註冊申請收到更新通知」的功能給會員申請使用呢
就是 RegisterObserver (我想申請當一個觀察者)

當然有註冊也要有取消再收到通知的功能
就是 RemoveObserver (我覺得煩 不想再收到通知了)

那是不是還少了通知的功能呢
就是 NotifyObserver (通知會員囉)

從Observer的角度來看,Object裡要有什麼功能呢?

收到從餐廳發來的更新會送到哪裡呢?會員的信箱、電話、地址等等。
這麼多個方法可以收到餐廳的更新通知,那就統一一個名稱吧
就是 Update() (因為收到更新後會員對餐廳的菜單就會進行資料更新呀)

從實作的角度來看,我們該怎麼實作觀察者模式

首先不管什麼模式核心理念都是物件與物件之間要鬆綁,不需要知道彼此的細節
鬆綁就是不要物件與物件之間直接呼叫,透過中間人來呼叫也就是介面

Java程式碼:
1. 建立觀察者的介面
public interface ClientObserver {
  public void update();
}

2. 建立主題的介面
public interface NewsPaperSubject {
  public void registerObserver(ClientObserver o);
  public void removeObserver(ClientObserver o);
  public void notifyObserver();
}

3. 建立主體物件
public class NewsPaper implements NewsPaperSubject {
  ArrayList clients = new ArrayList<>(); // storage observer list

  @Override
  public void registerObserver(ClientObserver o){
    clients.add(o);
  }

  @Override
  public void removeObserver(ClientObserver o){
    int i = clients.indexOf(o);
    if (i >=1) {
      clients.remove(i);
    }
  }

  @Override
  public void notifyObserver(){
     for(ClientObserver client : clients){
       client.update();
     }
  }
}

4. 建立觀察者物件
public class ATeamObserver implement ClientObserver{
  NewspaperSubject subject;

  public ATeamObserver(NewspaperSubject newsPaperSubject){
    subject = newsPaperSubject;
    subject.registerObserver(this);
  }

  @Override
  public void update(){
    //TODO: update data
  }

  public void cancelObserver()(
    subject.removeObserver();
  }
}

如果有新的觀察者加入不需要修改既有的程式碼
只需要再建一個新的觀察者物件並實作ClientObserver

只要有register加入newsPaperSubject的觀察者,當newsPaperSubject呼叫notifyObserver
都會收到通知進入update(),就可以各自處理收到通知後的行為
這種一對多即時更新的模式,就適用Observer Pattern

沒有留言:

張貼留言