定义
观察者模式(Observer Pattern)是一种行为型设计模式,允许一个对象(称为主题)维护一系列依赖于它的对象(称为观察者),并在主题状态改变时自动通知它们。这种模式主要用于实现事件处理系统、消息发布/订阅系统等,能够促进对象间的松耦合。
角色
- 主题(Subject):接口,用于添加、移除和通知观察者。
- 具体主题(Concrete Subject):实现Subject接口的类,当其内部状态改变时,通知注册的观察者。
- 观察者(Observer):为那些需要在主题状态改变时收到通知的对象定义一个接口。
- 具体观察者(Concrete Observer):实现Observer接口的类,根据主题的通知更新自身状态。
解决的问题
- 一对多的依赖关系:
- 当一个对象(被观察者,或称为主题)的状态变化时,所有依赖于它的对象(观察者)都得到通知并自动更新。这种一对多的依赖关系是观察者模式解决的核心问题。
- 弱耦合设计:
- 观察者模式支持松耦合设计。在这种设计中,被观察者不需要知道观察者的具体类,只需要知道观察者实现了特定的接口。这样,被观察者和观察者之间的耦合度降低,增加了系统的灵活性和可扩展性。
- 状态同步问题:
- 在某些场景下,需要确保一些对象的状态保持同步。观察者模式允许在无需使对象紧密耦合的情况下,实现状态的自动同步。
- 广播通信:
- 当一个对象的改变需要通知多个其他对象,且您希望避免使用紧密耦合系统时,观察者模式提供了一种实现广播通信的方式。
- 动态订阅和取消订阅:
- 观察者模式允许观察者在运行时动态地订阅或取消订阅主题,这为动态关系提供了灵活性。
使用场景
- 当一个对象的改变需要自动通知其他对象时:
- 如果一个对象的状态或数据的改变需要通知一个或多个其他对象,并且这些对象可能随时增加或减少,观察者模式提供了一种机制来动态地管理这些依赖关系。
- 当一个抽象模型有多个视图时:
- 观察者模式适用于模型-视图(Model-View)关系,特别是在GUI应用程序中,同一个数据模型可能有多个视图,当模型改变时,所有的视图都需要更新。
- 发布-订阅系统:
- 在需要发布/订阅功能的系统中,观察者模式可以作为一种实现机制。发布者(被观察者)发布消息,而订阅者(观察者)订阅并响应这些消息。
- 事件处理系统:
- 对于处理事件和事件监听的系统,如用户界面事件处理(按钮点击、鼠标移动等),观察者模式是一种标准的设计解决方案。
- 实现回调机制:
- 在需要回调的场景中,可以使用观察者模式来实现回调逻辑。对象可以注册其感兴趣的事件,并在事件发生时接收通知。
示例代码
// 主题接口
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 观察者接口
interface Observer {
void update(String message);
}
// 具体主题
class NewsPublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
public void setNews(String news) {
this.news = news;
notifyObservers();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// 具体观察者
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String news) {
System.out.println(name + " 收到新闻更新: " + news);
}
}
public class ObserverPatternDemo {
public static void main(String[] args) {
NewsPublisher publisher = new NewsPublisher();
Subscriber subscriber1 = new Subscriber("张三");
Subscriber subscriber2 = new Subscriber("李四");
publisher.registerObserver(subscriber1);
publisher.registerObserver(subscriber2);
publisher.setNews("Java 17 发布了!");
}
}
主要符合的设计原则
- 开闭原则(Open-Closed Principle):
- 观察者模式允许在不修改现有代码的情况下扩展系统,例如可以自由地添加新的观察者而不需要改变主题(被观察者)的代码。这意味着系统对于扩展是开放的,但对于修改是封闭的。
- 单一职责原则(Single Responsibility Principle):
- 在观察者模式中,主题负责维护观察者列表和通知观察者,而观察者负责处理通知。这种分离意味着每个类都只处理它自己的工作,符合单一职责原则。
- 依赖倒置原则(Dependency Inversion Principle):
- 观察者模式中,主题依赖于观察者的抽象,而不是具体的观察者类。观察者可以独立于主题变化,只要它们遵循相同的抽象接口或类。这样,细节(观察者)依赖于抽象(观察者接口或抽象类)。
- 里氏替换原则(Liskov Substitution Principle):
- 虽然观察者模式的应用通常不直接涉及继承,但它确保观察者可以被其子类替换而不影响程序的正确性。每个观察者的子类都应该能够替代其父类观察者而不破坏主题与观察者之间的关系。
在JDK中的应用
- java.util.Observer 和 java.util.Observable:
- 在JDK中,
Observer
接口和Observable
类是观察者模式的经典实现。虽然在Java 9中这个实现被标记为过时(主要是因为更好的事件监听器模式和响应式编程模型的出现),但它们仍然是观察者模式的一个标准例子。在这个模型中,Observable
对象代表被观察者,而Observer
接口的实现类代表观察者。
- 在JDK中,
- Java Beans 和 PropertyChangeListener:
- 在Java Beans中,
PropertyChangeListener
接口和PropertyChangeSupport
类实现了观察者模式。这使得当Bean的一个属性改变时,所有注册的PropertyChangeListener
都会收到通知。
- 在Java Beans中,
- Swing事件处理机制:
- Java Swing库广泛使用观察者模式来处理GUI事件。例如,使用按钮(
JButton
)时,可以向按钮添加一个或多个事件监听器(比如ActionListener
),当按钮被点击时,所有的监听器都会收到通知。
- Java Swing库广泛使用观察者模式来处理GUI事件。例如,使用按钮(
- Java事件监听器(EventListener):
- 事件监听器是观察者模式在Java中的另一个应用,尤其是在处理AWT和Swing事件时。对象可以注册为事件的监听器,并在事件发生时接收通知。例如,
MouseListener
和KeyListener
。
- 事件监听器是观察者模式在Java中的另一个应用,尤其是在处理AWT和Swing事件时。对象可以注册为事件的监听器,并在事件发生时接收通知。例如,
在Spring中的应用
- Spring事件发布-订阅机制:
- Spring提供了一个基于观察者模式的事件发布-订阅框架。在这个框架中,
ApplicationEventPublisher
接口用于发布事件,而ApplicationListener
接口用于接收事件。当一个事件被发布时,所有注册的监听器都会被通知。
- Spring提供了一个基于观察者模式的事件发布-订阅框架。在这个框架中,
- 自定义事件:
- 开发者可以创建自定义事件并通过实现
ApplicationListener
接口或使用@EventListener
注解来处理这些事件。这允许在应用程序中实现跨组件通信,同时保持组件之间的松耦合。
- 开发者可以创建自定义事件并通过实现
- 上下文事件:
- Spring提供了多种内置的上下文事件,如
ContextRefreshedEvent
,ContextStartedEvent
,ContextStoppedEvent
和ContextClosedEvent
。这些事件使得开发者能够在应用上下文的生命周期的特定点做出响应。
- Spring提供了多种内置的上下文事件,如
- 事务事件:
- 在Spring框架中,可以使用事务事件来通知不同组件事务的开始、提交或回滚。这是观察者模式在事务管理中的应用。