觀察者模式(Observer Pattern)定義了對象之間的一對多依賴,讓多個觀察者對象同時監聽一個主體對象,當主體對象發生變化時,它的全部依賴者(觀察者)都會收到通知並更新設計模式
屬於行爲型模式ide
觀察者模式有時也叫作發佈訂閱模式函數
適用場景: 觀察者模式主要用於在關聯行爲之間創建一套觸發機制的場景post
public class Per extends Observable{ private String name = "圈"; private static Per per = null; private Per(){} public static Per getInstance(){ if(null == per){ per = new Per(); } return per; } public String getName() { return name; } public void publishQuestion(Question question){ System.out.println(question.getUserName() + "在" + this.name + "上提交了一個問題。"); setChanged(); notifyObservers(question); } }
public class Question { private String userName; private String content; }
/** * 觀察者 */ public class Teacher implements Observer { private String name; public Teacher(String name){ this.name = name; } @Override public void update(Observable o, Object arg) { Per per = (Per)o; Question question = (Question)arg; System.out.println("==============================="); System.out.println(name + "老師,你好!\n" + "您收到了一個來自「" + per.getName() + "」的提問,但願您解答,問題內容以下:\n" + question.getContent() + "\n" + "提問者:" + question.getUserName()); } }
public static void main(String[] args) { Per per = Per.getInstance(); Teacher tom = new Teacher("FXD"); Teacher mic = new Teacher("DM"); Question question = new Question(); question.setUserName("小"); question.setContent("觀察者設計模式適用於哪些場景?"); per.addObserver(tom); per.addObserver(mic); per.publishQuestion(question); }
優勢: 1 觀察者和被觀察者之間創建了一個抽象的耦合this
2 觀察者模式支持廣播通訊google
缺點: 1 觀察者之間有過多的細節依賴、提升時間消耗及程序的複雜度設計
2 使用要得當,要避免循環調用server
/** * 監聽器的一種包裝,標準事件源格式的定義 * @author */ public class Event { /** * 事件源,事件是由誰發起的保存起來 */ private Object source; /** * 事件觸發,要通知誰 */ private Object target; /** * 事件觸發,要作什麼動做,回調 */ private Method callback; /** * 事件的名稱,觸發的是什麼事件 */ private String trigger; /** * 事件觸發的時間 */ private long time; public Event(Object target, Method callback) { this.target = target; this.callback = callback; } public Event setSource(Object source) { this.source = source; return this; } public Event setTime(long time) { this.time = time; return this; } public Object getSource() { return source; } public Event setTrigger(String trigger) { this.trigger = trigger; return this; } public long getTime() { return time; } public Object getTarget() { return target; } public Method getCallback() { return callback; } @Override public String toString() { return "Event{" + "\n" + "\tsource=" + source.getClass() + ",\n" + "\ttarget=" + target.getClass() + ",\n" + "\tcallback=" + callback + ",\n" + "\ttrigger='" + trigger + "',\n" + "\ttime=" + time + "'\n" + '}'; } }
/** * 監聽器,它就是觀察者 * @author */ public class EventListener { /** * JDK底層的Listener一般也是這樣來設計的 */ protected Map<String,Event> events = new HashMap<String,Event>(); /** * 事件名稱和一個目標對象來觸發事件 * @param eventType * @param target */ public void addLisenter(String eventType,Object target){ try { this.addListener( eventType, target, target.getClass().getMethod("on" + toUpperFirstCase(eventType),Event.class)); }catch (Exception e){ e.printStackTrace(); } } public void addListener(String eventType,Object target,Method callback){ //註冊事件 events.put(eventType, new Event(target, callback)); } /** * 觸發,只要有動做就觸發 * @param event */ private void trigger(Event event) { event.setSource(this); event.setTime(System.currentTimeMillis()); try { //發起回調 if(event.getCallback() != null){ //用反射調用它的回調函數 event.getCallback().invoke(event.getTarget(),event); } } catch (Exception e) { e.printStackTrace(); } } /** * 事件名稱觸發 * @param trigger */ protected void trigger(String trigger){ if(!this.events.containsKey(trigger)){return;} trigger(this.events.get(trigger).setTrigger(trigger)); } /** * 邏輯處理的私有方法,首字母大寫 * @param str * @return */ private String toUpperFirstCase(String str){ char[] chars = str.toCharArray(); chars[0] -= 32; return String.valueOf(chars); } }
public interface MouseEventType { /** * 單擊 */ String ON_CLICK = "click"; /** * 雙擊 */ String ON_DOUBLE_CLICK = "doubleClick"; /** * 彈起 */ String ON_UP = "up"; /** * 按下 */ String ON_DOWN = "down"; /** * 移動 */ String ON_MOVE = "move"; /** * 滾動 */ String ON_WHEEL = "wheel"; /** * 懸停 */ String ON_OVER = "over"; /** * 失焦 */ String ON_BLUR = "blur"; /** * 獲焦 */ String ON_FOCUS = "focus"; }
public class Mouse extends EventListener { public void click(){ System.out.println("調用單擊方法"); this.trigger(MouseEventType.ON_CLICK); } public void doubleClick(){ System.out.println("調用雙擊方法"); this.trigger(MouseEventType.ON_DOUBLE_CLICK); } public void up(){ System.out.println("調用彈起方法"); this.trigger(MouseEventType.ON_UP); } public void down(){ System.out.println("調用按下方法"); this.trigger(MouseEventType.ON_DOWN); } public void move(){ System.out.println("調用移動方法"); this.trigger(MouseEventType.ON_MOVE); } public void wheel(){ System.out.println("調用滾動方法"); this.trigger(MouseEventType.ON_WHEEL); } public void over(){ System.out.println("調用懸停方法"); this.trigger(MouseEventType.ON_OVER); } public void blur(){ System.out.println("調用獲焦方法"); this.trigger(MouseEventType.ON_BLUR); } public void focus(){ System.out.println("調用失焦方法"); this.trigger(MouseEventType.ON_FOCUS); } }
/** * 本身寫的邏輯,用於回調 * @author */ public class MouseEventCallback { public void onClick(Event e){ System.out.println("===========觸發鼠標單擊事件==========" + "\n" + e); } public void onDoubleClick(Event e){ System.out.println("===========觸發鼠標雙擊事件==========" + "\n" + e); } public void onUp(Event e){ System.out.println("===========觸發鼠標彈起事件==========" + "\n" + e); } public void onDown(Event e){ System.out.println("===========觸發鼠標按下事件==========" + "\n" + e); } public void onMove(Event e){ System.out.println("===========觸發鼠標移動事件==========" + "\n" + e); } public void onWheel(Event e){ System.out.println("===========觸發鼠標滾動事件==========" + "\n" + e); } public void onOver(Event e){ System.out.println("===========觸發鼠標懸停事件==========" + "\n" + e); } public void onBlur(Event e){ System.out.println("===========觸發鼠標失焦事件==========" + "\n" + e); } public void onFocus(Event e){ System.out.println("===========觸發鼠標獲焦事件==========" + "\n" + e); } }
public static void main(String[] args) { MouseEventCallback callback = new MouseEventCallback(); Mouse mouse = new Mouse(); //@誰? @回調方法 mouse.addLisenter(MouseEventType.ON_CLICK,callback); mouse.addLisenter(MouseEventType.ON_FOCUS,callback); mouse.click(); mouse.focus(); }
Guava對象
import com.google.common.eventbus.Subscribe; /** * @author */ public class GuavaEvent { @Subscribe public void subscribe(String str){ System.out.println("執行subscribe方法,傳入的參數是:" + str); } }
import com.google.common.eventbus.EventBus; /** * @author */ public class GuavaEventTest { public static void main(String[] args) { //消息總線 EventBus eventBus = new EventBus(); GuavaEvent guavaEvent = new GuavaEvent(); eventBus.register(guavaEvent); eventBus.post("m"); //從Struts到SpringMVC的升級 //由於Struts面向的類,而SpringMVC面向的是方法 //前面二者面向的是類,Guava面向是方法 //可以輕鬆落地觀察模式的一種解決方案 //MQ } }
Spring源碼: 事件
ContextLoaderListener