观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式的主要角色有:
- 主题(Subject):这是一个抽象类或接口,用于描述具体主题需要实现的方法,例如添加、删除观察者和通知观察者。
- 具体主题(ConcreteSubject):实现主题接口,具体主题需要维护一个观察者列表,当具体主题状态发生改变时,通知所有观察者。
- 观察者(Observer):这是一个抽象类或接口,用于描述具体观察者需要实现的方法,例如更新自己。
- 具体观察者(ConcreteObserver):实现观察者接口,当接收到具体主题的通知时,进行相应的操作。
优点:
- 观察者模式可以实现表示层和数据层的分离,使得数据层在状态发生改变时,可以通知所有观察者进行更新,而无需关心具体观察者的实现细节。
- 观察者模式有利于扩展,当有新的观察者需要添加时,只需实现观察者接口即可。
缺点:
- 观察者模式可能会导致循环依赖,当观察者和主题之间存在相互依赖时,可能会导致系统难以维护。
- 如果观察者太多,通知所有观察者可能会影响系统性能。
下面是一个使用 Java 实现的观察者模式的例子:
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String subjectState;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(subjectState);
}
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
notifyObservers();
}
}
// 观察者接口
interface Observer {
void update(String subjectState);
}
// 具体观察者
class ConcreteObserver implements Observer {
private String observerState;
@Override
public void update(String subjectState) {
observerState = subjectState;
System.out.println("观察者状态更新为:" + observerState);
}
}
public class ObserverPatternDemo {
public static void main(String[] args) {
// 创建具体主题
ConcreteSubject subject = new ConcreteSubject();
// 创建具体观察者
Observer observer1 = new ConcreteObserver();
Observer observer2 = new ConcreteObserver();
// 注册观察者
subject.registerObserver(observer1);
subject.registerObserver(observer2);
// 修改主题状态,通知观察者
subject.setSubjectState("新状态");
}
}
在这个例子中,我们创建了一个具体主题 ConcreteSubject 和两个具体观察者 ConcreteObserver。当具体主题的状态发生改变时,会通知所有注册的观察者进行更新。
使用场景:
案例一:聊天室程序
在聊天室程序中,当有新的消息到达时,需要通知所有在线的用户。这里可以使用观察者模式来实现。
具体实现如下:
- 创建一个主题接口
ChatRoomSubject,包含添加、删除观察者和通知观察者的方法。 - 创建一个具体主题
ChatRoom,实现主题接口,维护一个在线用户列表。当有新消息到达时,遍历用户列表并调用用户的receiveMessage方法通知他们有新消息。 - 创建一个观察者接口
User,包含接收消息的方法receiveMessage。 - 创建一个具体观察者
OnlineUser,实现观察者接口,代表在线用户。当收到新消息时,显示消息内容。
案例二:股票交易系统
在股票交易系统中,当股票价格发生变化时,需要通知所有关注该股票的投资者。这里可以使用观察者模式来实现。
具体实现如下:
- 创建一个主题接口
StockSubject,包含添加、删除观察者和通知观察者的方法。 - 创建一个具体主题
Stock,实现主题接口,维护一个关注该股票的投资者列表。当股票价格发生变化时,遍历投资者列表并调用投资者的updatePrice方法通知他们价格变化。 - 创建一个观察者接口
Investor,包含接收价格变化的方法updatePrice。 - 创建一个具体观察者
Trader,实现观察者接口,代表投资者。当收到股票价格变化时,根据新的价格做出相应的交易决策。
以下是使用 Java 实现股票交易系统的观察者模式的例子:
// 主题接口
interface StockSubject {
void registerObserver(Investor investor);
void removeObserver(Investor investor);
void notifyObservers();
}
// 具体主题
class Stock implements StockSubject {
private List<Investor> investors = new ArrayList<>();
private double price;
@Override
public void registerObserver(Investor investor) {
investors.add(investor);
}
@Override
public void removeObserver(Investor investor) {
investors.remove(investor);
}
@Override
public void notifyObservers() {
for (Investor investor : investors) {
investor.updatePrice(price);
}
}
public void setPrice(double price) {
this.price = price;
notifyObservers();
}
}
// 观察者接口
interface Investor {
void updatePrice(double price);
}
// 具体观察者
class Trader implements Investor {
private String name;
private double stockPrice;
public Trader(String name) {
this.name = name;
}
@Override
public void updatePrice(double price) {
this.stockPrice = price;
System.out.println(name + " 的股票价格更新为:" + stockPrice);
}
}
public class ObserverPatternDemo {
public static void main(String[] args) {
// 创建具体主题
Stock stock = new Stock();
// 创建具体观察者
Investor investor1 = new Trader("张三");
Investor investor2 = new Trader("李四");
// 注册观察者
stock.registerObserver(investor1);
stock.registerObserver(investor2);
// 修改股票价格,通知观察者
stock.setPrice(100.0);
}
}
在这个例子中,我们创建了一个具体主题 Stock 和两个具体观察者 Trader。当股票价格发生变化时,会通知所有关注该股票的投资者进行更新。