观察者模式
观察者模式是使用率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。
观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe) 模式、模型-视图(Model/View) 模式、源-监听器(Source/Listener) 模式或从属者(Dependents) 模式。观察者模式是一种对象行为型模式,所以我们使用的消息队列就是观察者模式中的一种。
观察者模式中包含以下几个角色:
被观察者(Observable): 是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
目标被观察者(ConcreteObservable): 是被观察者的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在被观察者类中定义的抽象业务逻辑方法(如果有的话) 。如果被观察者类是抽象类,并且无须扩展被观察者类,则目标被观察者类可以省略。
观察者(Observer): 对被观察者的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
具体观察者(ConcreteObserver): 在具体观察者中维护一个指向具体被观察者对象的引用,它存储具体观察者的有关状态,这些状态需要和具体被观察者对象的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体被观察者类的attach()方法将自己添加到被观察者类的集合中或通过detach()方法将自己从目标类的集合中删除。
下面我们看下具体的实现
第一步,被观察者对象,这个是百度百科的代码,是参照了Android的里面的监听器模式。
package observer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public abstract class Observable {
public final List<Class<?>> observerList = new ArrayList<Class<?>>();
//注册观察者,用于在观察者列表中新增观察者对象
public <T> void registerObserver(T ob) {
if (ob == null) throw new NullPointerException();
this.registerObserver(ob.getClass());
}
public void registerObserver(Class<?> cls) {
if (cls == null) throw new NullPointerException();
synchronized (observerList) {
if (!observerList.contains(cls)) {
observerList.add(cls);
}
}
}
//注销观察者对象,和register相对应,用于在观察者列表移除观察者对象
public <T> void unRegisterObserver(T ob) {
if (ob == null) throw new NullPointerException();
this.unRegisterObserver(ob);
}
public void unRegisterObserver(Class<?> cls) {
if (cls == null) throw new NullPointerException();
synchronized(observerList){
Iterator<Class<?>> iterator=observerList.iterator();
while(iterator.hasNext()){
if(iterator.next().getName().equals(cls.getName())){
iterator.remove();
break;
}
}
}
}
public void unRegisterAll() {
synchronized (observerList) {
observerList.clear();
}
}
public int countObservers() {
synchronized (observerList) {
return observerList.size();
}
}
/**
* notify all observer(通知所有观察者,在子类中实现)
*/
public abstract void notifyObservers(Object... objs);
/**
* notify one certain observer(通知某一个确定的观察者)
*/
public abstract void notifyObserver(Class<?> cls, Object... objs);
}
第二步,目标观察者对象
package observer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ConcreteObservable extends Observable {
private static ConcreteObservable instance = null;
private ConcreteObservable() {
}
public static synchronized ConcreteObservable getInstance() {
if (instance == null) {
instance = new ConcreteObservable();
}
return instance;
}
@Override
public void notifyObservers(Object... objs) {
for (Class<?> cls : observerList) {
notifyObserver(cls, objs);
}
}
@Override
public void notifyObserver(Class<?> cls, Object... objs) {
if (cls == null) throw new NullPointerException();
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals("update")) {
try {
String[] args = (String[]) objs[0];
System.out.println("目标被观察者对象数据发生变化,开始通知观察者,改变数据是:" + args[0]);
method.invoke(cls.newInstance(), objs);
break;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
}
}
第三步,观察者
package observer;
public interface Observer {
void update(Object...objs);
}
第四步,具体观察者
package observer;
public class ConcreteObserver implements Observer {
@Override
public void update(Object... objs) {
System.out.println("观察者发现数据变化: " + objs[0]);
}
}
第五步,测试
package observer;
public class ObserverTest {
public static void main(String[] args) {
ConcreteObservable concreteObservable = ConcreteObservable.getInstance();
concreteObservable.registerObserver(ConcreteObserver.class);
Observer observer = new ConcreteObserver();
concreteObservable.notifyObserver(observer.getClass() , new String[][]{new String[]{"123456", "654321"}});
}
}
第六步,输出
目标被观察者对象数据发生变化,开始通知观察者,改变数据是:123456
观察者发现数据变化: 123456
总结观察者模式就是这么简单,观察者模式在被观察者和观察者之间建立一个抽象的耦合,被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口,被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。而且观察者模式支持广播通讯,被观察者可以向所有的登记过的观察者发出通知。然后观察者模式还是有以下几个缺点:
1.如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间;
2.如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃;
3.虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
使用场景:
1.对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变;
2.对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
所以观察者模式在手机应用的开发中使用特别常见,Android手机开发所使用的Broadcast就是经典的观察者模式,譬如手机WIFI的打开和关闭,USB接口是否连接电脑都是有framework层的各个service将对应的消息发送出来,然后Android的应用动态的或者静态的监听实现对状态的更新。