Observer Pattern(觀察者模式)


一對多關係(Subject & Observer),實際資料位於主題(Subject)中,觀察者依附於主題,只要主題資料有更動,觀察者也會一併被通知

主題類別(要發送訊息的類別實作它)
   1:  package fpatterns.Observer_Pattern;
   2:   
   3:  public interface Subject {//主題
   4:      public void registerObserver(Observer ob);// 註冊觀察者
   5:   
   6:      public void removeObserver(Observer ob);// 移除觀察者
   7:   
   8:      public void notifyObservers();// 通知所有觀察者資料變動
   9:  }


觀察者類別(要接收訊息的類別實作它)
   1:  package fpatterns.Observer_Pattern;
   2:   
   3:  import java.util.ArrayList;
   4:   
   5:  interface Observer {// 觀察者
   6:      public void updateNum(ArrayList<Integer> al);// 所有觀察者更新資料
   7:  }


樂透開獎機(這是我的主題)
   1:  package fpatterns.Observer_Pattern;
   2:   
   3:  import java.util.ArrayList;
   4:  import java.util.Random;
   5:   
   6:  public class LottoSystem implements Subject, Runnable {// Runnable只用於方便開獎,沒有其他用途
   7:   
   8:      ArrayList<Observer> obsal;// 存放所有觀察者
   9:      ArrayList<Integer> numberal;// 存放樂透數字
  10:   
  11:      public LottoSystem() {
  12:   
  13:          obsal = new ArrayList<Observer>();
  14:          numberal = new ArrayList<Integer>();
  15:          for (int i = 0; i < 6; i++) {// 初始 6 個號碼為 0
  16:              numberal.add(0);
  17:          }
  18:      }
  19:   
  20:      public void registerObserver(Observer ob) {
  21:          obsal.add(ob);
  22:      }
  23:   
  24:      public void removeObserver(Observer ob) {
  25:          int i = obsal.indexOf(ob);
  26:          if (i >= 0) {
  27:              obsal.remove(i);
  28:          }
  29:      }
  30:   
  31:      // 主題更新資料之後,必須呼叫此方法以通知所有觀察者
  32:      public void notifyObservers() {
  33:   
  34:          for (int i = 0; i < obsal.size(); i++) {
  35:              Observer ob = (Observer) obsal.get(i);
  36:              ob.updateNum(numberal);
  37:          }
  38:   
  39:      }
  40:   
  41:      public void lottery() {
  42:          Random r = new Random();
  43:          for (int i = 0; i < numberal.size(); i++) {
  44:   
  45:              int tempnum = r.nextInt(48);
  46:   
  47:              for (int j = 0; j < numberal.size(); j++) {
  48:                  if (tempnum == numberal.get(j) && i != j) {
  49:                      tempnum = r.nextInt(48);
  50:                      j = 0;
  51:                      i = 0;
  52:                  }
  53:              }
  54:   
  55:              numberal.set(i, tempnum);
  56:          }
  57:   
  58:          notifyObservers();
  59:      }
  60:   
  61:      // 模擬開獎
  62:      public void run() {
  63:          while (true) {
  64:   
  65:              lottery();
  66:   
  67:              try {
  68:                  Thread.currentThread().sleep(1500);
  69:              } catch (InterruptedException e) {
  70:                  // TODO Auto-generated catch block
  71:                  e.printStackTrace();
  72:              }
  73:          }
  74:      }
  75:   
  76:  }



這是購買樂透的人(也是觀察者)
   1:  package fpatterns.Observer_Pattern;
   2:   
   3:  import java.util.ArrayList;
   4:   
   5:  public class ShowLottoNum implements Observer {
   6:   
   7:      String name;
   8:   
   9:      ArrayList<Integer> numlist;// 存放樂透數字
  10:   
  11:      Subject s;// 主題,用來註冊該觀察者
  12:   
  13:      // 當觀察者建構自己必須傳入已存在的主題物件以註冊自己本身
  14:      public ShowLottoNum(Subject s, String name) {
  15:          this.s = s;
  16:          s.registerObserver(this);
  17:          this.name = name;
  18:      }
  19:   
  20:      @Override
  21:      public void updateNum(ArrayList<Integer> al) {
  22:          // TODO Auto-generated method stub
  23:          numlist = al;
  24:          showNum();
  25:      }
  26:   
  27:      public void showNum() {
  28:          System.out.print(name + " get number :");
  29:          for (int i = 0; i < numlist.size(); i++) {
  30:              System.out.print(numlist.get(i) + ",");
  31:          }
  32:          System.out.println();
  33:      }
  34:   
  35:  }


測試程式
   1:  package fpatterns.Observer_Pattern;
   2:   
   3:  import java.util.ArrayList;
   4:  import java.util.List;
   5:   
   6:  public class Simulator {
   7:   
   8:      public static void main(String[] args) {
   9:   
  10:          LottoSystem ls = new LottoSystem();// 主題
  11:   
  12:          ShowLottoNum sln = new ShowLottoNum(ls, "John");// 觀察者1(若需要更多觀察者,只要照著
  13:                                                          // ShowLottoNum 建構即可 )
  14:          ShowLottoNum sln2 = new ShowLottoNum(ls, "Peter");// 觀察者2
  15:          ShowLottoNum sln3 = new ShowLottoNum(ls, "Little flower");// 觀察3
  16:   
  17:          // 開始開獎
  18:          new Thread(ls).start();
  19:      }
  20:   
  21:  }









標籤: