观察者模式(Observer Pattern)
观察者模式也叫做发布订阅模式(Publish/Subscribe)其定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。
观察者模式的优点:
1. 观察者和被观察者之间是抽象耦合。增加观察者还是被观察者都非常容易实现,只需实现相应的接口。
2. 可以建立一套触发机制。
观察模式的缺点:
观察者模式需要考虑开发效率和运行效率的问题,若一个被观察者有个多个观察者,由于Java中消息的通知默认是顺序的,一旦一个观察者卡壳就会产生严重的性能问题。而且观察者模式在调试的时候比较困难。
观察者模式的通用类图:
Observable(抽象被观察者角色):定义了被观察者必须实现的职责,它必须能够动态地增加、删除观察者,并且通知观察者。
Observer(抽象观察者角色):定义了观察者收到消息后,进行更新的接口。
ConcreteObservable(具体被观察者角色):定义了被观察者自己的业务逻辑,并且定义了对哪些事件进行通知。
ConcreteObserver(具体观察者角色):实现更新接口,对通知按自己的需求处理。
观察者模式的通用代码:
抽象被观察角色:
public interface Observable
{
/*定义可以动态添加观察者的接口*/
public void addObserver(Observer observer);
/*定义可以动态删除观察者的接口*/
public void removeObserver(Observer observer);
/*定义通知所有观察者的接口*/
public void notifyAllObservers();
}
抽象观察者角色:
public interface Observer
{
/*定义接到通知进行更新的接口*/
public void update();
}
具体被观察者角色:
public class ConcreteObservable implements Observable
{
/*存放观察该被观察者的观察者*/
private List<Observer> observers = new ArrayList<Observer>();
/*实现可以动态添加观察者的接口*/
@Override
public void addObserver(Observer observer)
{
this.observers.add(observer);
}
/*实现可以动态删除观察者的接口*/
@Override
public void removeObserver(Observer observer)
{
this.observers.remove(observer);
}
/*实现通知所有观察者的接口*/
@Override
public void notifyAllObservers()
{
for (Observer observer : this.observers)
{
observer.update();
}
}
/*被观察者自己的逻辑,并且定义了对该操作需要进行通知*/
public void logicMethod()
{
//逻辑处理
//通知所有观察者
this.notifyAllObservers();
//逻辑处理
}
}
具体观察者角色:
public class ConcreteObserver implements Observer
{
/*实现接到通知进行更新的接口*/
@Override
public void update()
{
System.out.println("接到通知!");
//处理消息
}
}
场景类:
public class Client
{
public static void main(String[] args)
{
/*被观察者*/
ConcreteObservable observable = new ConcreteObservable();
/*观察者*/
ConcreteObserver observer = new ConcreteObserver();
/*动态添加观察者*/
observable.addObserver(observer);
observable.logicMethod();
}
}
观察者模式扩展
扩展一:JDK提供的观察者模式支持
Java一开始就提供了一个可扩展的父类,既java.util.Observable,还提供了一个java.util.Observer接口。使用JDK提供的Observable和Observer后,每一个观察者只需要实现自己的逻辑方法就可以了,观察者的动态添加、删除,通知方法都由JDK为我们实现了。
扩展二:实用的观察者模式变形
1. 观察者与被观察者之间的消息沟通。在实际应用中的做法是:观察中的update方法接收两个参数,一个是被观察者,另一个是数据传输对象(一般是JavaBean,由被观察者生成,观察者消费,远程传输为XML)。
2. 观察者的响应方式。在一个观察者多个被观察对象的情况下,需要考虑性能问题。如果观察者对被观察者传来的数据响应速度过慢,会延长到被观察者的执行时间。观察者如何加快响应速度?第一种方式,使用多线程技术(异构),第二种方式,缓存技术。
3. 被观察者尽量自己做主。被观察者的状态改变不需要每次都通知观察者。一般对每个业务,如doSomething(),提供一个重载方法doSomething(boolen isNotify),来决定该状态变化是否通知观察者。