设计模式(二) - 观察者模式(Observer Pattern)

一、什么是观察者模式?

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

[观察者模式-类图]


观察者模式(Observer Pattern) = 主题(Subject) + 观察者(Observer)

● Subject(主题):主题又称为目标,它是指被观察的对象。在主题中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notifyObservers()。目标类可以是接口,也可以是抽象类或具体类(推荐使用接口,这样符合我们上一篇策略模式中提到的设计原则:多用组合少用继承;同时可以达到松耦合的目的)。

+

● ConcreteSubject(具体主题):具体主题是主题类的实现类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。

● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。

● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体主题对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的registerObserver()方法将自己添加到主题类的集合中,或者通过removeObserver()方法将自己从主题类的集合中删除。


二、代码示例

我们举一个气象站的例子:创建一个WeatherData对象(追踪来自气象站的数据,并更新布告板),和三个布告板(显示目前天气状况:温度、湿度、气压给用户看),一旦WeatherData对象有新的测量,这些布告必须马上更新。我们采用观察者模式来实现这个程序,并用WeatherData对象来实现Subject接口,当他来当“主题”,让布告板来实现Observer接口,来当我们的“观察者”。

接口包:

/**
 * 主题接口
 */
public interface ISubject {
    /**
     * 注册观察者
     * @param o 观察者
     */
    void registerObserver(IObserver o);

    /**
     * 移除观察者
     * @param o 观察者
     */
    void removeObserver(IObserver o);

    /**
     * 通知观察者
     */
    void notifyObservers();
}
/**
 * 观察者接口
 */
public interface IObserver {
    /**
     * 公共的更新方法
     * @param temperature 温度
     * @param humidity 湿度
     * @param pressure 气压
     */
    void update(float temperature, float humidity, float pressure);
}
/**
 * 用来展示的一个公共接口
 */
public interface IDisplayElement {
    void display();
}

具体的主题:

/**
 * 具体的主题
 */
public class WeatherData implements ISubject {
    private List<IObserver> observers;  // 用一个List来记录观察者
    private float temperature;  // 温度
    private float humidity;     // 湿度
    private float pressure;     // 气压

    public WeatherData() {
        observers = new ArrayList<>();
    }

    /**
     * 注册观察者
     * @param o 观察者
     */
    @Override
    public void registerObserver(IObserver o) {
        if (o == null)
            throw new NullPointerException();
        observers.add(o);
    }

    /**
     * 注销观察者
     * @param o 观察者
     */
    @Override
    public void removeObserver(IObserver o) {
        int i = observers.indexOf(o);
        if (i >= 0)
            observers.remove(i);
    }

    /**
     * 通知观察者
     */
    @Override
    public void notifyObservers() {
        // 这里我们把状态告诉每一个观察者。因为观察者都实现了update()方法,所以我们知道如何通知他们。
        for (IObserver o : observers) {
            o.update(temperature, humidity, pressure);
        }
    }

    /**
     * 当WeatherData从气象站得到更新观测值时,我们通知观察者
     */
    private void measurementsChanged() {
        notifyObservers();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值