定义
定义对象间的一种一对多的关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知,并被自动更新。
使用的原因
在应用程序开发过程中,往往都要求用户界面和业务逻辑分离,划定清晰的界限.因为应用程序要求能快速的更改用户界面并且不能对应用程序其他部分产生连带影响,而且业务逻辑也会发生变化并要求这一切变化与用户界面无关.观察者(observer)就是解决此问题最常用的设计模式,它非常有助于在系统中各个对象之间划分清晰的界限。
还有一种常见的情况,一个软件系统常常要求在某一个对象发生变化的时候,某些其它的对象做出相应的改变,而观察者模式是解决这个问题的一个低耦合度的设计方案,它能够减少对象之间的耦合以便更加利于系统的复用。
用JDK中的Observable接口和Observer类实现Observer模式
由于Observer模式使用范围很广,所以在JDK中提供了Observable接口和Observer类方便开发人员使用Observer模式,而且使用也很简单。
- 创建被观察者类,它继承自java.util.Observable类。
- 创建观察者类,它实现java.util.Observer接口;
- 对于被观察者类,添加它的观察者:
void addObserver(Observer o)
当被观察事件发生时,执行:
setChanged();
notifyObservers();
setChange()方法用来设置一个内部标志位注明数据发生了变化;notifyObservers()方法会去调用观察者对象列表中所有的Observer的update()方法,通知它们数据发生了变化。只有在setChange()被调用后,notifyObservers()才会去调用update()。
- 对于观察者类,实现Observer接口的唯一方法update
void update(Observable o, Object arg)
形参Object arg,对应一个由notifyObservers(Object arg);传递来的参数,当执行的是notifyObservers();时,arg为null。
public class NumsObservable extends Observable {
public final static Integer ODD = 1;
public final static Integer EVEN = 2;
private int data = 0;
public int getData() {
return data;
}
public void setData(int i) {
data = i;
Integer flag = EVEN;
if ((data & 0×0001) == 1)
flag = ODD;
setChanged();
notifyObservers(flag);
}
}
public class OddObserver implements Observer {
public void update(Observable o, Object arg) {
if (arg == NumsObservable.ODD) {
NumsObservable myObserable = (NumsObservable) o;
System.out.println("OddObserver:Data has changed to " + myObserable.getData());
}
}
S}
import java.util.Observable;
import java.util.Observer;
public class EvenObserver implements Observer {
public void update(Observable o, Object arg) {
if (arg == NumsObservable.EVEN) {
NumsObservable myObserable = (NumsObservable) o;
System.out.println("EvenObserver:Data has changed to " + myObserable.getData());
}
}
}
public class MultiTest {
public static void main(String[] args) {
NumsObservable number = new NumsObservable();
number.addObserver(new OddObserver());
number.addObserver(new EvenObserver());
number.setData(1);
number.setData(2);
number.setData(3);
}
}
在Spring框架中使用Observer模式
上面这个例程虽然很简单,但相信都大家了解了Observer模式的原理,而在实际的项目过称中,Observer模式的运用却复杂很多。例如,Observer对象本身还需要有很多依赖才能完成功能。下面这个例程针对的是如何在Spring框架下使用Observer模式,相信通过这段代码可以帮大家解决不少Observer模式使用的实际问题。
Subject接口代码
public interface Subject {
void addListener(Observer observer);
void removeListener(Observer observer);
void notifyListeners();
}
Subject的具体实现
public class ConcretSubject implements Subject {
private List<Observer> listeners=new ArrayList<Observer>();
public void addListener(Observer observer) {
listeners.add(observer);
}
public void notifyListeners() {
for (Observer observer : listeners) {
observer.update();
}
}
public void removeListener(Observer observer) {
listeners.remove(observer);
}
}
Observer接口代码
public interface Observer {
void update();
}
Observer接口的具体实现
public class ConcretObserver implements Observer{
public void update() {
System.out.println("ConcretObserver is updated");
}
}
以上内容都是很普通的Java类,跟【用JDK中的Observable接口和Observer类实现Observer模式】的代码样例很类似,不同的是【用JDK中的Observable接口和Observer类实现Observer模式】的这个样例中Observer是以代码的形式注册到Observerable实现类中的,而在这个例程中借助Spring框架的MethodInvokingFactoryBean我们用配置的方式来实现以上的功能。
<beans>
<bean id="subject" class="com.gaoke.simpleerp.service.impl.ConcretSubject" />
<bean id="observer" class="com.gaoke.simpleerp.service.impl.ConcretObserver" />
<bean id="registerConcretObserver"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<ref local="subject" />
</property>
<property name="targetMethod">
<value>addListener</value>
</property>
<property name="arguments">
<list>
<ref bean="observer" />
</list>
</property>
</bean>
</beans>
上面这个例程介绍的是如何通过Spring提供的MethodInvokingFactoryBean来实现Observer模式。由于Spring提供了强大的IOC容器功能,过Spring容器来实现Observer模式会让我们的应用程序开发的时候能更随心所欲:-)。
参考
Java:应用Observer接口实践Observer
Spring Loaded Observer Pattern