观察者模式
观察者模式也叫作发布 - 订阅模式,也就是事件监听机制。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
观察者模式的结构
一个软件系统常常要求在某一个对象状态发生变化时,某些其他的对象作出相应的改变。能做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。
观察者模式所涉及的角色有:
1、抽象主题角色
抽象主题角色把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2、具体主题角色
将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
3、抽象观察者角色
为所有的具体观察者提供一个接口,在得到主题通知时更新自己
4、具体观察者角色
存储与主题的状态相关的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态协调
观察者模式实例
抽象主题角色,有增加观察者、删除观察者、通知观察者的功能:
- public abstract class Subject {
- /** 用来保存注册的观察者对象 */
- private List list = new ArrayList();
- /** 注册观察者对象 */
- public void attch(Observer observer) {
- list.add(observer);
- System.out.println("Attached an observer");
- }
- /** 删除观察者对象 */
- public void detach(Observer observer) {
- list.remove(observer);
- System.out.println("Detached an observer");
- }
- /** 通知所有注册的观察者对象 */
- public void notifyObservers(String newState) {
- for (int i = 0; i < list.size(); i++) {
- list.get(i).update(newState);
- }
- }
- }
具体主题角色,这个 change 方法放在子类中是因为可能不同的主题在改变观察者状态的时候会做一些不同的操作,因此就不统一放在父类 Subject 里面了:
- public class ConcreteSubject extends Subject {
- private String state;
- public String getState() {
- return state;
- }
- public void change(String newState) {
- state = newState;
- System.out.println("主题状态为:" + state); // 状态发生改变时,通知各个观察者 this.notifyObservers(state); }}
观察者接口:
- public interface Observer {
- void update(String state);
- }
具体观察者实现了观察者接口:
- public class ConcreteObserver implements Observer {
- /** 观察者的状态 */
- private String observerState;
- public void update(String state) {
- /** 更新观察者的状态 */
- observerState = state;
- System.out.println("状态为:" + observerState);
- }
- }
客户端调用代码,一旦主题调用了 change 方法改变观察者的状态,那么观察者 Observer 里面的 observerState 全都改变了:
- public static void main(String[] args) {
- /** 创建主题角色 */
- ConcreteSubject subject = new ConcreteSubject();
- /** 创建观察者对象 */
- Observer observer = new ConcreteObserver();
- /** 将观察者注册到主题对象上 */
- subject.attch(observer);
- /** 改变主题对象的状态 */
- subject.change("new state");
- }
运行结果为:
- Attached an observer主题状态为:new state状态为:new state
这里只添加了一个观察者,有兴趣的可以试试看多添加几个观察者,效果都是一样的,主题角色改变状态,观察者状态全变。
观察者模式的两种模型
1、推模型
主题对象向观察者推送主题的详细信息,不管观察者是否需要。推送的信息通常是主题对象的全部或部分数据,上面的例子就是典型的推模型
2、拉模型
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中去获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过 update() 方法传递给观察者,这样观察者在需要获取数据的时候,就可以通过这个引用来获取了。
两种模型的比较
1、推模型是假设主题对象知道观察者需要的数据,拉模型是假设主题对象不知道观察者需要什么数据,干脆把自身传递过去,让观察者自己按需要取值
2、推模型可能会使得观察者对象难以复用,因为观察者的 update() 方法是按需要定义的参数,可能无法兼顾到没有考虑到的使用情况,这意味着出现新的情况时,可能要提供新的 update() 方法
观察者模式在 Java 中的应用及解读
JDK 是有直接支持观察者模式的,就是 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);
- }
- 这就是观察者的接口,定义的观察者只需要实现这个接口就可以了。update()方法,被观察者对象的状态发生变化时,被观察者的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);
- }
- }...
- }
- 这是被观察者的父类,也就是主题对象。这是一个线程安全的类,是基于Vector实现的。主题对象中有这些方法对观察者进行操作:
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: