觀察者模式是衆多軟件設計模式中的一種,又稱發佈訂閱模式.被觀察的對象發生了變化,觀察者對象們能夠第一時間收到通知,
並做出相應的處理,例如做爲一家餐館的會員,若餐館出了新品那麼會第一時間通知到各個會員,不是會員的路人則不會收到通知java再看一下類圖:設計模式
FoodSubject sub = new FoodSubject(); new LisaObserver(sub); Observer tom = new TomObserver(sub); System.out.println("----菜品發佈------"); Thread.sleep(1000); sub.onChange("剁椒魚頭", "80.00", "熱菜"); System.out.println("--- tom居然取消關注 ---"); sub.remove(tom); System.out.println("----又有菜品發佈哦------"); Thread.sleep(1000); sub.onChange("外婆菜炒蛋", "18.00", "熱菜");----菜品發佈------ 我是lisa, 食物:剁椒魚頭,價格:80.00,菜品類型:熱菜 我是tom, 食物:剁椒魚頭,價格:80.00,菜品類型:熱菜 --- tom居然取消關注 --- ----又有菜品發佈哦------ 我是lisa, 食物:外婆菜炒蛋,價格:18.00,菜品類型:熱菜
JDK已經幫咱們實現了觀察者模式,Observable至關於Subject,Observer同上自定義的Observer,只有一個方法:
//①.被觀察者對象,②.參數
void update(Observable o, Object arg);ideObservable是一個class而非一個接口
提供addObserver(Observer o)
deleteObserver(Observer o)測試notifyObservers()
notifyObservers(Object arg)
//必須在調用notifyObservers方法前先調用一次
//由於只有爲true時纔會通知觀察者
void setChanged()thispublic class News extends Observable{ private String subject; private String content; private Date date; public News() {} public void onChange(String subject, String content){ this.subject = subject; this.content = content; this.date = new Date(); setChanged(); notifyObservers(); } public String getSubject() { return subject; } public String getContent() { return content; } public Date getDate() { return date; } }
public class Person implements Observer, IShow { private News news; private String name; public Person(Observable subject, String name) { subject.addObserver(this); this.name = name; } @Override public void update(Observable o, Object arg) { if (o == null || !(o instanceof News)) { return; } news = (News) o; show(); } @Override public void show() { System.out.println("我是" + name + ",我閱讀了:\n 主題:" + news.getSubject() + "\n內容:" + news.getContent() + "\n發佈時間:" + news.getDate()); }若是觀察者對象不須要全部的參數 設計
public class Lisa implements Observer, IShow{ private News news; public Lisa(Observable subject) { subject.addObserver(this); } @Override public void show() { System.out.println("我是lisa,我閱讀了最新的新聞:\n 主題:" + news.getSubject() + ",內容:" + news.getContent()); } @Override public void update(Observable o, Object arg) { if(o == null || !(o instanceof News)){ return; } news = (News)o; show(); }
public interface IShow { void show(); }//測試 News news = new News(); System.out.println("----- 新聞資訊 -------"); String subject = "生態養海 擁海而興"; String content = "進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。"; new Tom(news); new Person(news,"any"); new Person(news,"tony"); new Person(news,"lexa"); Lisa lisa = new Lisa(news); news.onChange(subject, content); Thread.sleep(1000); System.out.println("lisa不感興趣,取消關住."); news.deleteObserver(lisa); Thread.sleep(1000); System.out.println("----- 又發佈了最新資訊 --------"); subject = "特朗普赦免感恩節火雞:它將擁有一個很是光明的將來"; content = "美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。"; news.onChange(subject, content);----- 新聞資訊 ------- 我是lisa,我閱讀了最新的新聞: 主題:生態養海 擁海而興,內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。 我是lexa,我閱讀了: 主題:生態養海 擁海而興 內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。 發佈時間:Thu Nov 23 16:53:16 CST 2017 我是tony,我閱讀了: 主題:生態養海 擁海而興 內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。 發佈時間:Thu Nov 23 16:53:16 CST 2017 我是any,我閱讀了: 主題:生態養海 擁海而興 內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。 發佈時間:Thu Nov 23 16:53:16 CST 2017 我是tom,我閱讀了: 主題:生態養海 擁海而興,內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。,發佈時間:Thu Nov 23 16:53:16 CST 2017 lisa不感興趣,取消關住. ----- 又發佈了最新資訊 -------- 我是lexa,我閱讀了: 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來 內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。 發佈時間:Thu Nov 23 16:53:18 CST 2017 我是tony,我閱讀了: 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來 內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。 發佈時間:Thu Nov 23 16:53:18 CST 2017 我是any,我閱讀了: 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來 內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。 發佈時間:Thu Nov 23 16:53:18 CST 2017 我是tom,我閱讀了: 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來,內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。,發佈時間:Thu Nov 23 16:53:18 CST 2017
由於Observable是一個「類」,你必須設計一個類繼承它。若是某類想同時
具備Observable類和另外一個超類的行爲,就會陷入兩難,畢竟Java不支持多重繼承。
這限制了Observable的複用潛力.
再者,由於沒有Observable接口,因此沒法創建本身的實現和Java內置的
Observer搭配使用,也沒法將java.util的實現換成另外一套作法的實現(比方說,
若是你可以擴展java.util.Observable,那麼Observable「可能」能夠符合你的需求。
不然,你可能須要像本章開頭的作法那樣本身實現這一整套觀察者模式。
並且setChanged()方法被保護起來了(被定義成protected)。這意味着:除非你繼承自Observable,不然你沒法建立Observable實例並組合到你本身的對象中來。code
-------------------------orm
//幾種事件類型:server
/** * Created by Bellamy.xiao on 2018/3/20. */ public enum EventType { ADD("ADD invoke","add evnet"), REMOVE("remove invoke", "add evnet."); private String invoke; private String evnet; private EventType(String invoke, String evnet) { this.invoke = invoke; this.evnet = evnet; } public String getInvoke() { return invoke; } public void setInvoke(String invoke) { this.invoke = invoke; } public String getEvnet() { return evnet; } public void setEvnet(String evnet) { this.evnet = evnet; } }//Event public class Event { private Object target; private Method callBack; private Date callTime; private String detail; public Event(Object target, Method callBack) { super(); this.target = target; this.callBack = callBack; } public Event() { } public Event(Object target, Method callBack, Date callTime, String detail) { super(); this.target = target; this.callBack = callBack; this.callTime = callTime; this.detail = detail; } public Event(Object target, Method callBack,String detail) { super(); this.target = target; this.callBack = callBack; this.detail = detail; } @Override public String toString() { return "Event [target=" + target + ", callBack=" + callBack + ", callTime=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(callTime) + ", detail=" + detail + "]"; } public Event(Object target, Method callBack, Date callTime) { super(); this.target = target; this.callBack = callBack; this.callTime = callTime; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Method getCallBack() { return callBack; } public void setCallBack(Method callBack) { this.callBack = callBack; } public Date getCallTime() { return callTime; } public void setCallTime(Date callTime) { this.callTime = callTime; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } }//事件監聽 public class EventListener { private Map<EventType, Event> events = new HashMap<EventType, Event>(); private void bind(Event e) { e.setCallTime(new Date()); try { e.getCallBack().invoke(e.getTarget(), e); } catch (Exception ex) { ex.printStackTrace(); } } public void bind(EventType type) { if (!this.events.containsKey(type)) { //這裏不在事件集合中的直接拋異常 throw new RuntimeException(type.getEvnet() + ",unknown!"); } this.bind(this.events.get(type)); } public void addListener(EventType type, Object tagert, Method m) { events.put(type, new Event(tagert, m, type.getInvoke())); } public void removeListener(EventType type) { events.remove(type); } }//回調通知 public class Observer { public void advice(Event e){ System.out.println(e); } }//測試代碼 public static void main(String[] args) throws Exception{ Method m = Observer.class.getMethod("advice",new Class[]{Event.class}); EventListener listener = new EventListener(); listener.addListener(EventType.ADD, new Observer(), m); listener.addListener(EventType.REMOVE, new Observer(), m); listener.bind(EventType.ADD); //移除事件再綁定測試 listener.removeListener(EventType.ADD); listener.bind(EventType.ADD); }//console:對象
Event [target=Observer@25154f, callBack=public void Observer.advice(Event), callTime=2018-03-21 16:51:49, detail=ADD invoke]Exception in thread "main" java.lang.RuntimeException: add evnet,unknown! at EventListener.bind(EventListener.java:23) at TestObserver.main(TestObserver.java:22)