> For the complete documentation index, see [llms.txt](https://jen-hsuan-hsieh.gitbook.io/design-pattern/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jen-hsuan-hsieh.gitbook.io/design-pattern/chapter2_guan_cha_zhe_mo_shi__observer_pattern.md).

# Chapter2: 觀察者模式 (Observer Pattern)

## This section contain the following items:

* 1.Observer Pattern
* 2.Observer Pattern Example: ItemController

## 1.Observer Pattern

* 觀察者模式要解決的問題:
  * 1.資料使用者或資料顯示者必須定期去取得最新資料, 而不是資料更新時通知更新
  * 2.實作上, 每當有新的項目要取得就必須改寫code
  * 3.實作上, 是針對具體物件實踐而不是介面
  * 4.在runtime時也無法新增或移除顯示項目
* 因此要如何解決以上問題呢? 就是利用觀察者模式
  * 主題 + 觀察者 = 觀察者模式 (以下圖片引用<深入淺出設計模式>)

![](/files/-M4M0Ln7qF99Pkj21Rev)

* 每當觀察者所定閱的主題有更新, 觀察者就會收到該物鍵的最新狀態
  * 當主題更新時觀察者們都會被通知, 彼此之間是被訂閱者與訂閱者的關係, 也就是說當被訂閱者改變狀態，其他訂閱者都會收到通知並自動被更新
* 一旦訂閱者解除訂閱便不會再收到通知
  * 示意圖如下 (以下圖片引用<深入淺出設計模式>)

![](/files/-M4M0Ln9dcNIBlHnrXTn)

* 角色(以下圖片引用<深入淺出設計模式>)
  * 主題物件 (Subject): 須實作以下功能
    * registerOberver()
    * removeOberver()
    * notifyOberver()
  * 觀察者 (Observer): 須實作以下功能
    * update()

![](/files/-M4M0LnBto7S6fXnJRPQ)

* 觀察者模式的優點
  * 1.們可在任何時間加入觀察者
  * 2.當加入/移除觀察者時不需要修改主題物件
  * 3.主題物件及觀察者皆是可以被重複使用的
  * 4.主題物件及觀察者的改變皆不會影響到彼此

    **2.Observer Pattern Example: ItemController**
* 1.需求
  * ItemController是MOXA Auto E-test Program的一環
  * 如下圖所示, ItemController為整個program的stage 1
  * 為滿足產品開發時的功能測試,stage 1要能達到以下的需求:

    * 1.可以遠端測試機器 (remote control)
    * 2.可以讓使用者編輯/擴充test case
    * 3.可以排程, 依序進行每個test case
    * 4.server端及client端皆可以產生簡單的test report並回傳

    ![](/files/-M4M0LnDdDMFAkFEUkGz)
* 2.軟體架構設計
  * ItemController的設計, 會在每一個test case的測試上都會喚起server, client
  * server, client即是Subject Object, 每一次test case的測試結束後所產生的report將會傳送給Observers
  * 因此架構中
    * 有一個IUser
      * Server, Client必須implement IUser
    * 有一個IOberver
      * Observer必須implement IObserver

![](/files/-M4M0LnFfz6whhM8_nw-)

* 3.程式碼解析
  * 當程式一執行, 會create Server, Client兩個物件, 並將TestItem.ini裡面所記載的觀察者名單依序註冊
  * IOberser

    ```
    public interface IObserver
    {
      string DefaultDrive { get; set; }
      string DefaultFolder { get; set; }
      string IP { get; set; }
      string Name { get; set; }
      string Password { get; set; }
      int GetTestReport(IUser user);
    ```

    }
  * IUser

    ```
    public interface IUser
    {
      string DefaultDrive{get;set;}
      string DefaultFolder { get; set; }
      string IP { get; set; }
      string Name { get; set; }
      string Password { get; set; }
      string TimeStamp { get; set; }
      string LogFileName { get; set; }
      string MachineName { get; set; }
      int returnValue { get; set; }
      List<string> TestReportsName { get; set; }
      List<string> TestItems { get; set; }
      List<string> Script { get; set; }
      int SetTestItems(ref List<string> testItems);
      int RunTestScript(int testItemNumber);
      void StartThread(object data);
      int WaitThread();
      int RegisterObserver(IObserver observer);
      int RemoveObserver(IObserver observer);
      int NotifyObservers();
    ```

    }
