《设计模式》之十五:观察者模式

Observer Pattern 观察者模式也叫发布/订阅(Publish/Subscribe)模式,它是一个在项目中经常使用的模式。

其定义如下:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

观察者模式的几个角色名称:

1,Subject被观察者

定义被观察者必须实现的职责,它必须能够动态增加、删除观察者,它一般是抽象类或实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者

2,Observer观察者

观察者接受到消息后,立即进行update,对接受的信息进行处理

3,ConcreteSubject具体的被观察者

定义被观察者自己的业务逻辑,同时定义对那些事件进行通知

4,ConcreteObserver具体观察者

通用模板代码:

public interface Observer {
    // 更新方法
    public void update();
}
public class ConcreteObserver implements Observer {
    @Override
    public void update() {
        System.out.println("接受到消息,并处理中...");
    }
}
public abstract class Subject {
    // 定义一个观察者数组
    private Vector<Observer> observers = new Vector<Observer>();

    // 增加一个观察者
    public void addObserver(Observer o) {
        this.observers.add(o);
    }

    // 删除一个观察者
    public void delObserver(Observer o) {
        this.observers.remove(o);
    }

    // 通知所有观察者
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update();
        }
    }
}
public class ConcreteSubject extends Subject {
    // 具体业务逻辑
    public void doSomething() {
        // do something...
        System.out.println("I do something...");
        super.notifyObservers();
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建一个被观察者
        ConcreteSubject subject = new ConcreteSubject();
        // 定义一个观察者
        Observer obs = new ConcreteObserver();
        // 添加观察者
        subject.addObserver(obs);
        // 开始活动
        subject.doSomething();
    }
}

观察者模式的优点:

1,观察者和被观察者之间是抽象耦合的

如此则不管是增加观察者还是增加被观察者都非常容易扩展,而且在Java中都已经实现的抽象层的定义,在系统扩展方面更是得心应手。

2,建立一套除非机制

观察者模式的缺点:

观察者模式需要考虑一下开放效率和运行效率问题,一个被观察者,多个观察者,开放和调试就比较复杂。Java中消息通知模式是顺序执行,这种情况下,一般采用异步方式的消息通知机制。

多级触发的效率更是让人担忧。这时候要注意啦啦

观察者模式使用场景:

1,关联行为场景。注意的是,关联行为是可拆分的,而不是组合关系。

2,事件多级触发场景

3,扩系统的消息交换场景,如消息队列的处理机制

注意事项:

广播链的问题:

只要注意一点,根据经验建议,一个观察者模式中最多出现一个对象既是观察者又是被观察者,也就是说消息最多转发一次(传递两次)。

异步处理问题:

有多个观察者的时候,如果观察者处理时间较长就要使用异步方式,那这个时候就得考虑线程安全和队列的问题,这时候可以参考下Message Queue就有更深入的理解。

观察者模式的扩展模式:

在JDK中已经给我们提供了现成的Observable和Observer两个类,之间使用即可大大简化上面的代码:
这时候已经不需要抽象的Subject和自己定义的Observer类了:

public class ConcreteSubject extends Observable {
    // 具体业务逻辑
    public void doSomething() {
        // do something...
        System.out.println("I do something...");
        super.setChanged();
        super.notifyObservers();
    }
}
public class ConcreteObserver implements java.util.Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("---哈哈,我在使用JDK里面的Observer接受到消息---");
    }
}

项目中真实的观察者模式:

1,观察者和被观察者之间的消息沟通

一般做法是:观察者中的update方法有两个参数,一个是被观察者,一个是DTO,DTO是一个纯洁的JavaBean,由被观察者生产,由观察者消费。 从JDK的Observer接口即可看出来。

如果考虑远程传输,一般消息格式以XML或者JSON格式传递。

2,观察者响应方式:

一般来讲是启动多线程去通知观察者

3,被观察者尽量自己做主

被观察者状态改变是否一定要通知观察者呢?不一定的这个,一般对被观察者的业务逻辑doSomething方法实现重载,如增加一个doSomething(boolean isNotifyObs)方法,决定是否通知观察者,而不是在消息到达观察者时才判断要不要处理这个消息。

最佳实践:

观察者模式在实践项目和生活中经常出现,举几个例子说明:

1,文件系统

一个目录小新建一个文件,会同时通知目录管理器增加一个目录,并通知磁盘管理器减少1K空间

2,广播收音机

电台在广播,你可以打开两个收音机来收听,电台就是被观察者,收音机就是观察者。

本人博客已搬家,新地址为:http://yidao620c.github.io/

相关推荐