一 定义
观察者模式也叫做发布订阅模式,是一种使用率非常高的设计模式。
定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
二 模式结构
角色介绍:
- Subject:抽象主题,也就是被观察者的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
- ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过得观察者发送通知,具体主题角色又被叫做具体观察者角色。
- Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。
- ConcreteObserver:具体观察者,该角色实现抽象观察者角色所定义的更新接口,以便在主题的状态发生变化时更新自身的状态。
三 实例
观察者模式的通用代码如下:
- 抽象观察者Observer接口,主要完成在收到通知后更新自己。
public interface Observer {
// 更新方法
void update();
}
- 具体的观察者ConcreteObserver,实现抽象观察者中定义的接口,在收到通知后更新自己。
public class ConcreteObserver implements Observer {
@Override
public void update() {
System.out.println("接收到更新通知,更新!");
}
}
- 被观察者角色Subject,主要是定义了一个被观察者数组,实现注册,移除观察者,通知观察者更新等。
public abstract class Subject {
// 定义一个观察者数组
private List mObservers=new ArrayList<>();
/**
* 注册观察者对象
* @param o
*/
public void addObserver(Observer o){
this.mObservers.add(o);
}
/**
* 移除观察者对象
* @param o
*/
public void deleteObserver(Observer o){
this.mObservers.remove(o);
}
/**
* 通知所有观察者更新
*/
public void notifyObserver(){
for (Observer observer:mObservers){
observer.update();
}
}
}
- 具体的被观察者ConcreteObserver,实现自己的业务逻辑。
public class ConcreteSubject extends Subject{
/**
* 具体的业务逻辑
*/
public void doSomething(){
super.notifyObserver();
}
}
- 测试代码
// 创建一个被观察者
ConcreteSubject subject=new ConcreteSubject();
// 定义一个观察者
Observer observer=new ConcreteObserver();
// 注册观察者
subject.addObserver(observer);
// 开始观察
subject.doSomething();
具体结果就不贴了,注册观察者后,被观察者会发送通知,通知到观察者,观察者收到通知后,更新自己。
下面,我们以订阅开发者论坛的技术文章为例,Android 开发者网站是google专门向android开发者提供技术支持的专业社区,开发者可以通过邮件订阅的方式订阅上面的文章。在这里,开发者相当于观察者,Android 开发者网站相当于被观察者。
实际上,针对观察者模式,Java向我们提供了观察者和被观察对象,在Java的实用工具类库java.util包下,我们可以直接使用,下面可以看下源码。
- 观察者Observer接口,主要定义了一个可用于数据更新的接口。
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an Observable object's
* notifyObservers
method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the notifyObservers
* method.
*/
void update(Observable o, Object arg);
}
- 被观察者Observable,可以看到,Observable源码也是实现了addObserver,deleteObserver,notifyObservers等方法。
public class Observable {
private boolean changed = false;
private Vector obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
/**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* Deletes an observer from the set of observers of this object.
* Passing null
to this method will have no effect.
* @param o the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/**
* If this object has changed, as indicated by the
* hasChanged
method, then notify all of its observers
* and then call the clearChanged
method to
* indicate that this object has no longer changed.
*
* Each observer has its update
method called with two
* arguments: this observable object and null
. In other
* words, this method is equivalent to:
*
* notifyObservers(null)
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* If this object has changed, as indicated by the
* hasChanged
method, then notify all of its observers
* and then call the clearChanged
method to indicate
* that this object has no longer changed.
*
* Each observer has its update
method called with two
* arguments: this observable object and the arg
argument.
*
* @param arg any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
// Android-changed: Call out to hasChanged() to figure out if something changes.
// Upstream code avoids calling the nonfinal hasChanged() from the synchronized block,
// but that would break compatibility for apps that override that method.
// if (!changed)
if (!hasChanged())
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();
}
/**
* Marks this Observable object as having been changed; the
* hasChanged method will now return true.
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* Indicates that this object has no longer changed, or that it has
* already notified all of its observers of its most recent change,
* so that the hasChanged method will now return false.
* This method is called automatically by the
* notifyObservers
methods.
*
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* Tests if this object has changed.
*
* @return true
if and only if the setChanged
* method has been called more recently than the
* clearChanged
method on this object;
* false
otherwise.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#setChanged()
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* Returns the number of observers of this Observable object.
*
* @return the number of observers of this object.
*/
public synchronized int countObservers() {
return obs.size();
}
}
以下是具体的代码:
- 观察者角色,观察者实现了Observer接口,只要实现一个update()方法就能接受到更新。
public class Developer implements Observer {
private String name;
public Developer(String name){
this.name=name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("你好,"+name+",Android开发网站更新啦,内容:"+arg);
}
}
- 被观察者角色,实现Observable,在这里可以实现自己的业务逻辑,本实例实现了一个发布新技术的方法。
public class DevelopTribune extends Observable {
// 自己的业务逻辑
public void postNewPublish(String content){
// 标识状态发生改变
setChanged();
// 通知所有观察者
notifyObservers(content);
}
}
- 测试代码
// 被观察者
DevelopTribune developTribune=new DevelopTribune();
// 观察者
Developer developer1=new Developer("Lucy");
Developer developer2=new Developer("James");
Developer developer3=new Developer("Jackson");
// 注册观察者
developTribune.addObserver(developer1);
developTribune.addObserver(developer2);
developTribune.addObserver(developer3);
// 发布更新
developTribune.postNewPublish("新技术来袭!");
-
运行结果
四 优缺点
优点:
- 观察者和被观察者之间是抽象耦合,应对业务变化,非常容易扩展。
- 增强系统灵活性,可扩展性。
缺点:
在运用观察者模式需要考虑效率问题,即存在一个被观察者和多个观察者的时候,开发和调试会比较复杂,如果一个观察者卡壳,会影响整体的执行效率。
五 使用场景
- 关联行为场景,关联行为要是可拆分的,而不是组合关系。
- 事件多级触发场景
- 跨系统信息交换场景