设计模式 - 观察者模式
一、引入
观察者模式就好像是你订阅了一个邮件列表,当邮件列表中有新的消息时,你会收到通知。在软件设计中,观察者模式允许一个对象(称为“主题”或“被观察者”)维护一组依赖它的对象(称为“观察者”),并在状态变化时通知所有观察者。
举个例子,想象你在一个新闻网站上订阅了一些新闻类别,比如体育、科技、娱乐等。当有新的新闻发布时,你会收到相应类别的通知。这里,你就是观察者,新闻网站就是被观察者。
二、概念
观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。当主题对象的状态发生变化时,所有依赖于它的观察者都会得到通知并自动更新。
三、基本结构
- Subject(主题):
- 定义了一个抽象接口,用于添加、删除和通知观察者对象。
- 具体主题(ConcreteSubject)实现了主题接口,维护了一个观察者列表,并在状态发生变化时通知观察者。
- Observer(观察者):
- 定义了一个更新的接口,用于接收主题的通知并进行相应的处理。
- 具体观察者(ConcreteObserver)实现了观察者接口,在接收到通知时执行相应的操作。
四、示例代码
主题相关:
/**
* 主题接口 : 也称为被观察者或可观察者,它是一个具有状态的对象,当状态发生变化时会通知所有的观察者。
*/
public interface Subject {
/**
* 注册观察者
*
* @param observer
*/
void registerObserver(Observer observer);
/**
* 删除观察者
*
* @param observer
*/
void removeObserver(Observer observer);
/**
* 通知观察者
*/
void notifyObservers();
}
/**
* 具体主题对象
*/
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
/**
* 注册观察者
*
* @param observer
*/
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
/**
* 删除观察者
*
* @param observer
*/
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
/**
* 通知观察者
*/
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
}
观察者:
/**
* 观察者接口 : 定义了一个更新方法,用于在接收到主题的通知时更新自己的状态。
*/
public interface Observer {
/**
* 更新数据
*
* @param message
*/
void update(String message);
}
/**
* 观察者A
*/
public class ConcreteObserverA implements Observer {
@Override
public void update(String message) {
System.out.println("观察者A收到消息: " + message);
}
}
/**
* 观察者B
*/
public class ConcreteObserverB implements Observer{
@Override
public void update(String message) {
System.out.println("观察者B收到消息:" + message);
}
}
客户端:
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
//观察者a
Observer observerA = new ConcreteObserverA();
//观察者b
Observer observerB = new ConcreteObserverB();
//注册到主题
subject.registerObserver(observerA);
subject.registerObserver(observerB);
subject.setMessage("5435");
}
}
五、能干什么
- 对象间的松耦合:观察者模式可以降低对象之间的直接依赖关系,使得主题和观察者之间相互独立,可以单独变化,而不会影响对方。
- 一对多的通信:观察者模式支持一对多的通信机制,一个主题可以同时通知多个观察者,适用于需要广播通知的场景。
- 事件处理:当一个事件发生时,可以通过观察者模式来通知所有关注该事件的观察者,实现事件的处理和响应。
- 消息通知:例如,一个新闻网站发布了一篇新的文章,需要通知所有订阅了该类别的用户。
- 模块解耦:通过观察者模式,可以将一个模块拆分成两个独立的部分,一个负责产生事件,另一个负责处理事件,从而实现模块之间的解耦。
- 实现广播机制:例如,一个股票价格变动时,需要通知所有关注该股票的投资者。
六、总结
优点:
- 松耦合(Loose Coupling):主题和观察者之间的关系是松耦合的,它们不直接依赖于彼此的具体实现。这使得可以动态地添加、移除观察者,而不影响主题和观察者之间的交互。
- 支持广播通信:当主题状态发生变化时,所有注册的观察者都会收到通知。这种一对多的通信机制非常适合事件处理、消息通知等场景。
- 扩展性强:可以轻易地添加新的观察者,扩展系统功能。
- 降低对象间的直接依赖关系:主题和观察者之间只依赖于抽象接口,不依赖于具体实现,使得系统更灵活、可维护。
缺点:
- 可能导致内存泄漏:如果观察者没有被正确地移除,可能会导致内存泄漏。
- 通知顺序不确定:由于观察者是异步执行的,所以观察者接收通知的顺序是不确定的。
- 可能引起性能问题:如果通知操作涉及复杂的逻辑或者大量的观察者,可能会影响系统的性能。
- 增加调试难度:由于观察者模式将系统分散为许多小对象,因此在调试时可能需要跟踪多个对象之间的交互。