在说观察者模式之前,我们先来说下设计模式的几大原则:
单一职责原则
开放关闭原则
里氏代换原则
依赖倒转原则
接口隔离法则
迪米特法则
观察者模式:
又称发布–订阅模式(有时又称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)。观察者模式完美的将观察者和被观察者的对象分离开,举个例子,用户界面作为观察者,业务数据作为被观察者,两者之间存在“观察”的逻辑,用户界面观察业务数据的变化,当被观察者(业务数据)发生变化时,观察者(用户界面)就会观察到到变化,并作出相应的响应。
实现:
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
以上,我们可以看出,观察者模式主要用于解耦,将观察者和被观察者解耦,让两者之间没有依赖或者依赖关系很小。
应用:
Android四大组件之一的BroadcastReceiver,实际上也是一个典型的观察者模式,通过sendBroadcast发送广播时候,只有注册了相应的IntentFilter的BroadcastReceiver对象才会收到这条广播消息,进而做出响应。
另外,现在比较流行的第三方框架很多也是用的观察者模式,例如EventBus、RxJava、RxAndroid、otto等等。在这里就不拿其中一个作为例子解析。
角色说明
Subject(抽象主题):又叫抽象被观察者,把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject(具体主题):又叫具体被观察者,将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
Observer (抽象观察者):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,当得到主题更改通知时更新自身的状态。
具体实现例子
让我们用父亲通知儿子做事的例子来说明
1、创建抽象观察者—Observer
定义一个接到通知的更新方法,即儿子们接到通知后的反应
public interface Observer {
public void updata(String msg);
}
2、创建具体观察着(即儿子们)—ConcrereObserver
public class SonSeaObserver implements Observer {
private String name;
public SonSea(String name) {
this.name = name;
}
@Override
public void updata(String msg) {
System.out.println(name+"收到了消息:"+msg+"后开始傲娇拒绝");
}
}
public class SonZhenObserver implements Observer {
private String name;
public SonZhen(String name) {
this.name = name;
}
@Override
public void updata(String msg) {
System.out.println(name+"收到了消息:"+msg+"屁颠屁颠照做了");
}
}
3、创建抽象主题----Subject
即抽象被观察者,定义添加、删除、通知等方法
public interface Observable {
void add(Observer observer);
void remove(Observer observer);
void notify(String msg);
}
4、创建具体主题—ConcreteSubject
即具体被观察者(父亲),发布通知
public class FatherObservable implements Observable {
private List<Observer> sonList = new ArrayList<>();
@Override
public void add(Observer observer) {
sonList.add(observer);
}
@Override
public void remove(Observer observer) {
sonList.remove(observer);
}
@Override
public void notify(String msg) {
for (Observer observer : sonList){
observer.updata(msg);
}
}
}
5、具体测试
private void testObserver(){
Observable fatherOb = new FatherOb();
SonSea sonSea = new SonSea("海海");
SonZhen sonZhen = new SonZhen("大正");
fatherOb.add(sonSea);
fatherOb.add(sonZhen);
fatherOb.notify("去扑街啦");
}
6、理解
实际上,JDK内部也内置了Observable(抽象被观察者),Observer(抽象观察者)这两个类,我们也可以直接拿来用,其代码如下:
public interface Observer {//(抽象观察者
//只定义了一个update方法
void update(Observable o, Object arg);
}
public class Observable {//抽象被观察者
private boolean changed = false;//定义改变状态,默认为false
private final ArrayList<Observer> observers;//定义一个观察者list
public Observable() {//构造函数,初始化一个观察者list来保存观察者
observers = new ArrayList<>();
}
//添加观察者,带同步字段的,所以是线程安全的
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!observers.contains(o)) {
observers.add(o);
}
}
//删除观察者
public synchronized void deleteObserver(Observer o) {
observers.remove(o);
}
//通知所以观察者,无参数
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察者,带参数
public void notifyObservers(Object arg) {
Observer[] arrLocal;
//加synchronized字段,保证多线程下操作没有问题
synchronized (this) {
if (!hasChanged())//这里做了是否发生改变的判断,是为了防止出现无意义的更新
return;
arrLocal = observers.toArray(new Observer[observers.size()]);//ArrayList转换成一个临时的数组,这样就防止了通知,添加,移除同时发生可能导致的异常
clearChanged();///清除改变状态,设置为false
}
//遍历逐一通知
for (int i = arrLocal.length-1; i>=0; i--)
arrLocal[i].update(this, arg);
}
//清楚所有观察者
public synchronized void deleteObservers() {
observers.clear();
}
//设置被观察者为改变状态,设置为true
protected synchronized void setChanged() {
changed = true;
}
//清除改变状态,设置为false
protected synchronized void clearChanged() {
changed = false;
}
//返回当前的改变状态
public synchronized boolean hasChanged() {
return changed;
}
//观察者数量
public synchronized int countObservers() {
return observers.size();
}
}
优点
缺点