观察者模式的应用场景
觀察者模式(Observer Pattern)定義了對象之間的一對多依賴,讓多個觀察者對象同時監聽一個主體對象,當主體對象發生變化時,它的所有依賴者(觀察者)都會收到通知并更新,屬于行為型模式。觀察者模式有時也叫做發布訂閱模式。觀察者模式主要用于在關聯行為之間建立一套觸發機制的場景。觀察者模式在現實生活應用也非常廣泛,比如:微信朋友圈動態通知、消息通知、郵件通知、廣播通知、桌面程序的事件響應等(如下圖)。
現在大家都用過我們的生態圈了,當小伙伴們在生態圈中提問的時候,如果有設置指定老師回答,對應的老師就會收到郵件通知,這就是觀察者模式的一種應用場景。我們有些小伙伴可能會想到MQ,異步隊列等,其實JDK 本身就提供這樣的API。我們用代碼來還原一下這樣一個應用場景,創建GPer 類:
public class GPer extends Observable{private String name = "GPer生態圈";private static GPer gper = null;private GPer(){}public static GPer getInstance(){if(null == gper){gper = new GPer();}return gper;}public String getName() {return name;}public void publishQuestion(Question question){System.out.println(question.getUserName() + "在" + this.name + "上提交了一個問題。");setChanged();notifyObservers(question);} }創建問題Question 類:
public class Question {private String userName;private String content;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getContent() {return content;}public void setContent(String content) {this.content = content;} }創建老師Teacher 類:
public class Teacher implements Observer {private String name;public Teacher(String name){this.name = name;}public void update(Observable o, Object arg) {GPer gper = (GPer)o;Question question = (Question)arg;System.out.println("===============================");System.out.println(name + "老師,你好!\n" +"您收到了一個來自“" + gper.getName() + "”的提問,希望您解答,問題內容如下:\n" +question.getContent() + "\n" +"提問者:" + question.getUserName());} }客戶端測試代碼:
public class ObserverTest {public static void main(String[] args) {GPer gper = GPer.getInstance();Teacher tom = new Teacher("Tom");Teacher mic = new Teacher("Mic");//這為沒有@Tom老師Question question = new Question();question.setUserName("小明");question.setContent("觀察者設計模式適用于哪些場景?");gper.addObserver(tom);gper.addObserver(mic);gper.publishQuestion(question);}}在下面我們再來設計一個業務場景,幫助小伙伴更好的理解觀察者模式。JDK 源碼中,觀察者模式也應用非常多。例如java.awt.Event 就是觀察者模式的一種,只不過Java 很少被用來寫桌面程序。我們自己用代碼來實現一下,以幫助小伙伴們更深刻地了解觀察者模式的實現原理。首先,創建Event 類:
/*** 監聽器的一種包裝,標準事件源格式的定義*/ 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;}@Overridepublic String toString() {return "Event{" + "\n" +"\tsource=" + source.getClass() + ",\n" +"\ttarget=" + target.getClass() + ",\n" +"\tcallback=" + callback + ",\n" +"\ttrigger='" + trigger + "',\n" +"\ttime=" + time + "'\n" +'}';} }創建EventLisenter 類:
/*** 監聽器,它就是觀察者*/ public class EventLisenter {//JDK底層的Lisenter通常也是這樣來設計的protected Map<String,Event> events = new HashMap<String,Event>();//事件名稱和一個目標對象來觸發事件public void addLisenter(String eventType,Object target){try {this.addLisenter(eventType,target,target.getClass().getMethod("on" + toUpperFirstCase(eventType),Event.class));}catch (Exception e){e.printStackTrace();}}public void addLisenter(String eventType,Object target,Method callback){//注冊事件events.put(eventType, new Event(target, callback));}//觸發,只要有動作就觸發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();}}//事件名稱觸發protected void trigger(String trigger){if(!this.events.containsKey(trigger)){return;}trigger(this.events.get(trigger).setTrigger(trigger));}//邏輯處理的私有方法,首字母大寫private String toUpperFirstCase(String str){char[] chars = str.toCharArray();chars[0] -= 32;return String.valueOf(chars);}}創建MouseEventType 接口:
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"; }創建Mouse 類:
public class Mouse extends EventLisenter {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);} }創建回調方法MouseEventCallback 類:
/*** 自己寫的邏輯,用于回調*/ 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 class MouseEventTest {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();} }?
總結
以上是生活随笔為你收集整理的观察者模式的应用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 装饰者模式的优缺点
- 下一篇: 观察者模式在源码中的应用