观察者模式的概念
观察者模式(Observer Pattern)是一种软件设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有依赖它的观察者对象,使它们能够自动更新自己。观察者模式又被称为发布-订阅模式、模型-视图模式、源-监听器模式或从属者模式。
观察者模式的优缺点
优点:
- 降低对象之间的耦合性:观察者模式是一种松散的耦合模式,它让主题和观察者之间实现了松散的耦合关系。这样可以使得两者可以独立地改变和复用。
- 支持广播通信:主题对象可以同时通知多个观察者对象,而不需要知道这些观察者对象的具体数量或类型。
- 符合开闭原则:可以在不修改主题对象和观察者对象源代码的前提下,通过增加新的观察者类型或主题类型来扩展系统的功能。
缺点:
- 性能问题:如果主题对象有很多的直接和间接的观察者对象,那么在主题对象状态发生变化时,通知所有的观察者对象会花费很多时间。
- 循环依赖:如果观察者对象和主题对象之间存在循环依赖关系,那么当主题对象状态发生变化时,可能会导致系统崩溃。
- 无法知道观察目标的变化细节:观察者模式只通知观察者目标对象发生了变化,但没有提供相应的机制让观察者知道目标对象是怎么发生变化的。
观察者模式的应用场景
- 事件处理:在图形用户界面(GUI)框架中,按钮的点击事件、窗口的打开和关闭事件等都可以使用观察者模式进行处理。
- 消息通知:在聊天应用、社交媒体平台等需要实时消息传递的场景中,可以使用观察者模式实现消息的发布和订阅。
- 股票市场:股票市场中的行情变化可以看作是一个主题对象,而各个投资者可以看作是观察者对象。当行情发生变化时,可以通知所有的投资者进行更新。
- 日志记录:在实时日志记录系统中,日志记录器可以看作是被观察者对象,而日志分析器、报警系统等可以看作是观察者对象。当日志发生变化时,可以通知这些观察者对象进行相应的处理。
观察者模式的代码实现
在Java中,可以使用接口和类来实现观察者模式。下面是一个简单的示例代码:
// 定义主题接口 | |
public interface Subject { | |
void registerObserver(Observer o); // 注册观察者 | |
void removeObserver(Observer o); // 移除观察者 | |
void notifyObservers(); // 通知所有观察者 | |
// 其他业务方法... | |
} | |
// 定义观察者接口 | |
public interface Observer { | |
void update(String message); // 更新方法,接收主题对象发送的消息 | |
} | |
// 具体主题类 | |
public class ConcreteSubject implements Subject { | |
private List<Observer> observers = new ArrayList<>(); | |
private String state; // 主题状态 | |
// 注册观察者 | |
@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(state); | |
} | |
} | |
// 其他业务方法... | |
public void setState(String state) { | |
this.state = state; | |
notifyObservers(); // 状态变化时通知所有观察者 | |
} | |
} | |
// 具体观察者类 | |
public class ConcreteObserver implements Observer { | |
private String name; // 观察者名称 | |
public ConcreteObserver(String name) { | |
this.name = name; | |
} | |
// 更新方法 | |
@Override | |
public void update(String message) { | |
System.out.println(name + " received message: " + message); | |
} | |
} |
在这个示例中,Subject
接口定义了主题对象需要实现的方法,包括注册观察者、移除观察者和通知所有观察者。Observer
接口定义了观察者对象需要实现的方法,即更新方法。ConcreteSubject
类实现了Subject
接口,并维护了一个观察者列表。当主题状态发生变化时,它会调用notifyObservers()
方法通知所有观察者。ConcreteObserver
类实现了Observer
接口,并在更新方法中打印接收到的消息。