一對多關係(Subject & Observer),實際資料位於主題(Subject)中,觀察者依附於主題,只要主題資料有更動,觀察者也會一併被通知
主題類別(要發送訊息的類別實作它)
public interface Subject {//主題
public void registerObserver(Observer ob);// 註冊觀察者
public void removeObserver(Observer ob);// 移除觀察者
public void notifyObservers();// 通知所有觀察者資料變動
}
觀察者類別(要接收訊息的類別實作它)
import java.util.ArrayList;
interface Observer {// 觀察者
public void updateNum(ArrayList<Integer> al);// 所有觀察者更新資料
}
樂透開獎機(這是我的主題)
import java.util.ArrayList;
import java.util.Random;
public class LottoSystem implements Subject, Runnable {// Runnable只用於方便開獎,沒有其他用途
ArrayList<Observer> obsal;// 存放所有觀察者
ArrayList<Integer> numberal;// 存放樂透數字
public LottoSystem() {
obsal = new ArrayList<Observer>();
numberal = new ArrayList<Integer>();
for (int i = 0; i < 6; i++) {// 初始 6 個號碼為 0
numberal.add(0);
}
}
public void registerObserver(Observer ob) {
obsal.add(ob);
}
public void removeObserver(Observer ob) {
int i = obsal.indexOf(ob);
if (i >= 0) {
obsal.remove(i);
}
}
// 主題更新資料之後,必須呼叫此方法以通知所有觀察者
public void notifyObservers() {
for (int i = 0; i < obsal.size(); i++) {
Observer ob = (Observer) obsal.get(i);
ob.updateNum(numberal);
}
}
public void lottery() {
Random r = new Random();
for (int i = 0; i < numberal.size(); i++) {
int tempnum = r.nextInt(48);
for (int j = 0; j < numberal.size(); j++) {
if (tempnum == numberal.get(j) && i != j) {
tempnum = r.nextInt(48);
j = 0;
i = 0;
}
}
numberal.set(i, tempnum);
}
notifyObservers();
}
// 模擬開獎
public void run() {
while (true) {
lottery();
try {
Thread.currentThread().sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
這是購買樂透的人(也是觀察者)
import java.util.ArrayList;
public class ShowLottoNum implements Observer {
String name;
ArrayList<Integer> numlist;// 存放樂透數字
Subject s;// 主題,用來註冊該觀察者
// 當觀察者建構自己必須傳入已存在的主題物件以註冊自己本身
public ShowLottoNum(Subject s, String name) {
this.s = s;
s.registerObserver(this);
this.name = name;
}
@Override
public void updateNum(ArrayList<Integer> al) {
// TODO Auto-generated method stub
numlist = al;
showNum();
}
public void showNum() {
System.out.print(name + " get number :");
for (int i = 0; i < numlist.size(); i++) {
System.out.print(numlist.get(i) + ",");
}
System.out.println();
}
}
測試程式
import java.util.ArrayList;
import java.util.List;
public class Simulator {
public static void main(String[] args) {
LottoSystem ls = new LottoSystem();// 主題
ShowLottoNum sln = new ShowLottoNum(ls, "John");// 觀察者1(若需要更多觀察者,只要照著
// ShowLottoNum 建構即可 )
ShowLottoNum sln2 = new ShowLottoNum(ls, "Peter");// 觀察者2
ShowLottoNum sln3 = new ShowLottoNum(ls, "Little flower");// 觀察3
// 開始開獎
new Thread(ls).start();
}
}
在〈Observer Pattern(觀察者模式)〉中有 2 則留言
[…] 基本上 Observer Pattern 是用來取代 polling 的解決方案。關於Observer Pattern 可以參考這篇 […]
[…] 主動模式會應用觀察者模式 (Observer Pattern) 來控制整個流程。首先 Model 就是主題 (Subject),而 View 和 Controller 則都是觀察者 (Observer)。 […]