观察者模式
当对象之间存在一对多的关系时,可以使用观察者模式。
事例引入
现在有一个温度系统,这个系统有许多的用户,当温度改变时,该系统便会通知所有的用户,更新用户的温度信息。

若不使用观察者模式,这样的一个系统该如何实现呢?如下:
public class TemperatureSystem {
User userA;
User userB;
User userC;
public void temperatureChange(double temperature){
userA.setTemperature(temperature);
userB.setTemperature(temperature);
userC.setTemperature(temperature);
}
}
温度系统直接拥有这三个用户,当温度被改变时,调用temperatureChange方法,将三个用户的温度信息直接改变。
这个系统看上去没有问题,但是现在有了新需求:由于这个系统太好用了!(真的吗?),有个用户D也想加入进来,它也想在温度变化时被通知,那上述的代码该如何维护呢?它需要修改原来的代码!再和userD强耦合,然后在temperatureChange方法里添加进userD,这不仅麻烦,还违反了开闭原则:对修改关闭,对拓展开放。
同理,如果用户B觉得这套系统不好用,想退出,那也不得不修改原先的代码…
由上述的需求例子,我们对这套系统有了这样的需求:
- 当有用户加入该系统时,不需要修改代码
- 当有用户退出该系统时,不需要修改代码
- 当温度变化时,需要通知所有的用户
观察者模式的角色
- 观察者:需要收到信息的角色,对应上述例子中的用户
- 主题:通知观察者们信息的角色,对应上述例子中的温度系统
观察者模式的代码实现
主题接口 Subject
该接口主要有三个方法:
registerObserver():将一个用户注册成为观察者removeObserver():将一个观察者从主题中移除notifyObserver():通知所有的观察者,并给它们传输新的数据
public interface Subject {
void registerObserver();
void removeObserver();
void notifyObserver();
}
观察者接口 Observer
观察者接口仅需要持有update方法即可
public interface Observer {
void update(double temperature);
}
主题类 TemperatureSystem
主题类需要实现主题接口,并且实现接口的三个方法
主题类持有一个list来存储所有的观察者,当有观察者注册时,将其添加到list中,反之亦然
而当主题类更新它的属性temperature时,需要通知所有的观察者,并将数据传输给所有的观察者,即调用观察者的update方法
public class TemperatureSystem implements Subject{
private ArrayList<Observer> list;
private double temperature;
public TemperatureSystem() {
list = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
@Override
public void notifyObserver() {
for (Observer observer : list) {
observer.update(temperature);
}
}
public void setTemperature(double temperature) {
this.temperature = temperature;
notifyObserver();
}
}
观察者类 User
观察者类需要持有一个主题对象,以方便注册和移除(当然也可以不持有)
当用户初始化时,便可以将自己注册成为一个观察者,当然也可以手动注册成为观察者,要看具体需求了
public class User implements Observer{
private String name;
private double temperature;
private Subject subject;
public User(String name, Subject subject) {
this.name = name;
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(double temperature) {
this.temperature=temperature;
display();
}
public void removeObserver(){
subject.removeObserver(this);
}
private void display(){
System.out.println(name + "收到温度" + temperature);
}
}
测试类 Main
public class Main {
public static void main(String[] args) {
TemperatureSystem subject = new TemperatureSystem();
User userA = new User("用户A",subject);
User userB = new User("用户B",subject);
User userC = new User("用户C",subject);
subject.setTemperature(52);
userB.removeObserver();
subject.setTemperature(13.14);
}
}
输出
用户A收到温度100.0
用户B收到温度100.0
用户C收到温度100.0
用户A收到温度13.14
用户C收到温度13.14
总结
- 如果需要注册新的用户成为观察者时,并不需要修改原来的代码,仅需要将其注册即可
- 若用户不想成为观察者时,也仅需要将其移除即可
- 同时在主题状态改变时,会通知所有的观察者以发送消息
本文介绍了观察者模式,一种用于处理对象一对多关系的设计模式。通过一个温度系统的实例,展示了在没有使用观察者模式时遇到的问题,以及采用观察者模式后如何优雅地解决这些问题。文章详细阐述了观察者模式的角色,包括观察者和主题,并提供了相应的接口定义和代码实现,说明了如何注册、移除观察者以及在主题状态改变时通知所有观察者。
1899

被折叠的 条评论
为什么被折叠?



