必須做作業三:Network-Monitor觀察者模式解析
一、總述
觀察者模式,由觀察者和被觀察物件組成,java已經提供了相關類供我們開發者呼叫!
當資料變化時,Observable會通知集合裡的所有觀察者物件!具體在資料變化後,app呼叫Observable的notifyObservers方法,那麼 集合裡的所有Observer的update()會被執行!
設計其實很簡單,當資料要發生改變時,被觀察者observable將會呼叫相關方法通知觀察者物件集合裡的所有觀察者,然後集合裡所有的observer再呼叫自己的方法更新自己的狀態。
其中observe和observable類直接是呼叫java函式
1、觀察者模式類圖:
2、github地址:
https://github.com/shonegg/NetMonitor
觀察者與被觀察者來自JAVA自帶的類。
具體被觀察者:https://github.com/shonegg/NetMonitor/blob/master/library/src/main/java/com/net/framework/NetObservable.java
具體觀察者:https://github.com/shonegg/NetMonitor/blob/master/library/src/main/java/com/net/framework/NetObserver.java
二、觀察者模式具體分析
1、被觀察者(Observable)
在github裡作者直接用import 匯入了observable類,所以我在官方文件裡找到了observable類的程式碼(由於程式碼過長,刪掉了部分註釋)
package java.util; public class Observable { private boolean changed = false; private Vector obs; /** Construct an Observable with zero Observers. */ public Observable() { obs= new Vector(); } public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } /** * Clears the observer list so that this object no longer has any observers. */ public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this <tt>Observable</tt> object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } }<span style="font-size:18px;"> </span>
- 我們可以看出,被觀察者類給出了新增觀察者物件、刪除觀察者物件、通知觀察者物件等方法,被觀察者物件即可直接繼承,重寫一些方法。
2.具體被觀察者 (NetObservable)
package com.net.framework; /** * Author Shone * Date 04/07/16. * Github https://github.com/shonegg */ import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import java.util.Observable; import java.util.Observer; public class NetObservable extends Observable { private Context context; public NetObservable(Context context) { super(); this.context = context; } @Override public void addObserver(Observer observer) { try { super.addObserver(observer); NetworkInfo networkInfo = Network.getCurrentActiveNetwork(this.context); if (networkInfo != null) { if (!networkInfo.isAvailable()) { observer.update(this, new NetObserver.NetAction(false, false, Network.getSubType(context))); return; } if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { observer.update(this, new NetObserver.NetAction(true, true, Network.getSubType(context))); return; } observer.update(this, new NetObserver.NetAction(true, false, Network.getSubType(context))); return; } observer.update(this, new NetObserver.NetAction(false, false, Network.getSubType(context))); } catch (Exception e) { e.printStackTrace(); } } @Override public void notifyObservers(Object data) { try { this.setChanged(); super.notifyObservers(data); } catch (Exception e) { e.printStackTrace(); } } }
- 這裡setChanged()是關鍵,她將內部標誌置為真changed = true,下面是通知父方法
- 以上的被觀察者物件重新寫了addObsever方法,這個方法是為了在增加觀察者的時候,馬上得到觀察者當前的網路狀態。
- 該被觀察者物件還重新寫了notifyObsevers的方法(通過呼叫this.setChanged(),再呼叫其父類被觀察者類中的通知方法,setChanged()是用來設定被觀察者的狀態已經被改變,改變之後,notifyObserver()方法會通知所要訂閱主題物件的觀察者,呼叫其 update()方法。)
- 這部分也是直接import自帶庫中的observer類,這裡直接貼出來官方文件(刪掉部分註釋)
- 我們可以看出,類中只包含了update方法,當收到被觀察者網路發生改變呼叫notifyobservers方法時,用來更新觀察者的網路狀態。
/* * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * */ package java.util; */ public interface Observer { void update(Observable o, Object arg); }
4、具體觀察者:
package com.net.framework; /** * Author Shone * Date 04/07/16. * Github https://github.com/shonegg */ import java.util.Observable; import java.util.Observer; public abstract class NetObserver implements Observer { public static class NetAction { private boolean isAvailable; private boolean isWifi; private Network.Type type; public NetAction(boolean isAvailable, boolean isWifi, Network.Type type) { super(); this.isAvailable = isAvailable; this.isWifi = isWifi; this.type = type; } public boolean isAvailable() { return this.isAvailable; } public Network.Type getType() { return type; } public void setType(Network.Type type) { this.type = type; } public boolean isWifi() { return this.isWifi; } } public abstract void notify(NetAction action); @Override public void update(Observable observable, Object data) { this.notify(((NetAction) data)); } }
- 觀察者物件NetAction中有一個列舉類成員Network.Type,詳細描述了是哪一種網路:
- 觀察者物件擴充套件了netaction方法,用來儲存被觀察者傳下來的具體訊息(如網路種類、wifi等)
- 當一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。在我們的這個網路監控中,觀察者依賴於被觀察者。
- 當對一個物件的改變需要同時改變其它物件,而不知道具體有多少個物件待改變。當被觀察者的資料要發生改變時,對應的觀察者的資料也要改變,這個時候只要將被觀察者裡的觀察者集合都改變了就可以了
- 當一個物件必須通知其它物件,而它又不能假定其它物件是誰。換句話說,你不希望這些物件是緊密耦合的。
- 在觀察者和被觀察者之間建立了一個耦合,對於被觀察者來說,他只對它的觀察者集合負責,然後具體的網路改變都是通過介面傳遞,只需要改變setchange()與Notifyobservers()即可,剩下的不需要被觀察者在意。被觀察者也不需要知道觀察者都有些誰。
- 而對於觀察者而言,它不需要知道被觀察者的情況,只需要知道介面傳下來的netaciton(具體動作如網路狀態、WiFi改變),執行自己的update()更新自己的狀態即可。
- 它們沒有緊密的耦合,可以屬於不同的抽象化層次
- 一旦資料改變,支援廣播通訊很適合被觀察者向每一個觀察者廣播改變網路狀態的通知。