必须做作业三: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()方法。)
3、观察者:observer
- 这部分也是直接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()更新自己的状态即可。
- 它们没有紧密的耦合,可以属于不同的抽象化层次
- 一旦数据改变,支持广播通信很适合被观察者向每一个观察者广播改变网络状态的通知。