Java设计模式 十五 观察者模式 (Observer Pattern)

观察者模式 (Observer Pattern)

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象(即观察者)都会得到通知并自动更新。观察者模式常用于事件处理系统、发布/订阅模式等场景中。


1. 观察者模式的组成

观察者模式主要由以下角色组成:

  • Subject(主题或被观察者): 被观察的对象,它保持所有观察者的列表,并在自身状态变化时通知所有观察者。
  • Observer(观察者): 接受通知并根据主题的变化更新自己状态的对象。每个观察者都需要实现一个更新方法,用来响应主题的变化。
  • ConcreteSubject(具体主题): 具体的被观察者,它实现了主题接口并通知观察者更新。
  • ConcreteObserver(具体观察者): 具体的观察者,它对主题的变化作出反应,通常是更新自身的状态。

2. 观察者模式的工作流程

  1. 观察者对象向主题(被观察者)注册自己。
  2. 主题对象维护一个观察者列表。
  3. 当主题状态发生变化时,它会通知所有注册的观察者。
  4. 观察者对象接收到通知后,更新自己的状态。

3. 观察者模式的实现

场景示例:天气预报系统

假设我们有一个天气预报系统,其中有多个用户(观察者)想要实时接收天气变化的通知。我们可以使用观察者模式来实现这个功能。


1) 定义观察者接口

观察者接口包含一个update方法,用于接收主题的通知。

// 观察者接口
public interface Observer {
    void update(String weather);
}

2) 定义主题接口

主题接口包含添加、移除观察者的方法和通知观察者的方法。

// 主题接口
public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

3) 定义具体主题(WeatherStation)

ConcreteSubject 实现了 Subject 接口,并在状态发生变化时通知所有观察者。

import java.util.ArrayList;
import java.util.List;

// 具体主题
public class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String weather;

    // 添加观察者
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    // 移除观察者
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    // 通知所有观察者
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(weather);
        }
    }

    // 设置天气并通知观察者
    public void setWeather(String weather) {
        this.weather = weather;
        notifyObservers();
    }
}

4) 定义具体观察者(PhoneDisplay 和 DesktopDisplay)

每个观察者会在接收到通知时更新自己的状态。

// 具体观察者1:手机显示
public class PhoneDisplay implements Observer {
    private String weather;

    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }

    public void display() {
        System.out.println("Phone Display: Current weather is " + weather);
    }
}

// 具体观察者2:桌面显示
public class DesktopDisplay implements Observer {
    private String weather;

    @Override
    public void update(String weather) {
        this.weather = weather;
        display();
    }

    public void display() {
        System.out.println("Desktop Display: Current weather is " + weather);
    }
}

5) 客户端代码

在客户端代码中,创建主题对象和观察者对象,并注册观察者。

public class Client {
    public static void main(String[] args) {
        // 创建天气站(主题)
        WeatherStation weatherStation = new WeatherStation();
        
        // 创建观察者
        Observer phoneDisplay = new PhoneDisplay();
        Observer desktopDisplay = new DesktopDisplay();
        
        // 注册观察者
        weatherStation.addObserver(phoneDisplay);
        weatherStation.addObserver(desktopDisplay);
        
        // 更新天气,通知所有观察者
        weatherStation.setWeather("Sunny");
        weatherStation.setWeather("Rainy");
    }
}

运行结果:
Phone Display: Current weather is Sunny
Desktop Display: Current weather is Sunny
Phone Display: Current weather is Rainy
Desktop Display: Current weather is Rainy

4. 观察者模式的优点

  1. 解耦: 主题和观察者之间是松耦合的,主题不需要知道观察者的具体类,只知道它们实现了 Observer 接口。
  2. 动态更新: 当主题状态变化时,所有注册的观察者都会自动更新,无需手动调用每个观察者。
  3. 扩展性: 可以方便地增加新的观察者,且无需修改已有代码,符合开闭原则。

5. 观察者模式的缺点

  1. 多次通知: 当有很多观察者时,主题每次更新时都需要通知所有观察者,这可能导致性能问题。
  2. 依赖性: 虽然观察者和主题松耦合,但主题的改变仍然会影响到观察者的行为,这使得系统中仍然存在一定的依赖关系。
  3. 可能导致内存泄漏: 如果观察者未能正确地从主题中注销,可能会导致内存泄漏,因为主题仍然持有对观察者的引用。

6. 观察者模式的应用场景

  • 事件监听器: GUI编程中的事件监听,用户点击按钮时,所有的监听器都会被触发。
  • 发布/订阅系统: 例如,在消息队列、广播系统、RSS订阅等场景中,主题发布消息,所有订阅者(观察者)都接收该消息。
  • 系统日志监控: 监控系统中的某个事件变化时,多个不同模块(观察者)需要做出响应。

7. 总结

观察者模式是一种非常常见且实用的设计模式,它通过一对多的方式,帮助实现对象之间的松耦合通信。主题和观察者的解耦使得它非常适用于动态变化和事件驱动的应用场景,特别是在GUI、消息通知、系统监控等领域具有广泛应用。

环境:Windows XP professional, JDK 1.6, Eclipse 3.3 Europa. 我们说学习Java应该从Swing开始,那么学习Swing最重要的思想就是对于观察者模式的理解(Observer Pattern)。因为,该设计模式Java Swing框架中贯穿了始终。对于C#的委托、代理概念所使用的Callback(回调模式--参见本人的“第一个C#程序Hello World ”资源)来看,Java Swing编程是纯粹的OO语言、是一种非常优雅的编程语言(本人认为)--而C#的学习好像非常强调所谓的OO思想,但是不是知道是什么OO思想?(个人观点,请勿激动)。 该示例是翻写一老外Observer Pattern的例子,本人觉得该示例是对该模式的非常精典的说明,于是花点功夫来翻写它,因为他的代码没有注释说明该模式的设计思想怎样体现在代码中去,所以,本人结合代码注释了关键代码的中文意义说明作者怎样表示该设计模式的,以方便Java程序员阅读和理解代码,从而理解该设计模式的思想(本人的注释非常详尽)。 目的,本人认为,作为Java程序员--不是指只会使用JBuilder(或者Websphare等)工具拖拽的java操作员--我们指至少能使用Eclipse工具书写Swing代码的Java编程员,或者使用ant工具编程的Java程序员,应该熟练掌握该设计模式!因为该设计模式贯穿Swing框架的始终。 阅读对象:本锦江中心中从S1阶段就想成为一个Java程序员的学员,并且在S1阶段已经非常认真的学习Java编程的学员。 注:不过该代码应该是本锦江中心Y2阶段Java方向学习的学员的参考代码,因为,该代码是由Y2阶段本教员会讲解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十方来财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值