定义
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象。这个对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
优缺点
优点:
- 松耦合:观察者和被观察者之间是抽象耦合的,具体观察者不需要知道被观察者的具体实现细节,只需要实现统一的接口即可。当被观察者发生改变时,无需修改各个具体的观察者类。
- 可扩展性:增加新的观察者非常方便,只需要继承或实现观察者接口并注册到被观察者中即可。
- 灵活性:在被观察者状态变化时,能够自动通知所有依赖它的观察者对象,使系统具有良好的响应性和灵活性。
- 广播机制:一个主题可以同时拥有多个观察者,这样,在状态变化时,主题只需触发一次更新操作,就能将信息广播给所有观察者。
缺点:
- 循环依赖:如果设计不当,可能会导致观察者和被观察者之间产生循环依赖,造成系统难以维护。
- 性能开销:如果观察者数量庞大且更新频繁,每次通知所有观察者都会有一定的性能开销。
- 顺序问题:由于所有的观察者都是异步执行的,无法保证通知的顺序,对于需要按照特定顺序更新的场景不适用。
- 内存泄漏:如果观察者和被观察者之间的生命周期管理不当,可能会导致内存泄露。例如,某个观察者不再使用但未从被观察者列表移除,就会造成内存资源无法释放。
- 代码复杂度增加:在某些简单场景下,为了实现观察者模式可能引入额外的复杂性,如果实际需求并不需要解耦或者事件驱动,则可能得不偿失。
结构图和示例
- Subject类:主题或者抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
- Observer类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者接口实现。
- ConcreteSubject类:叫做具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
- ConcreteObserver类:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
示例:
/**
* 抽象通知者
*/
public interface class Subject {
// 绑定观察者
public void attach(Observer observer);
// 移除观察者
public void detach(Observer observer);
// 通知观察者
public void notifyObserver();
}
/**
* 抽象观察者
*/
public interface Observer {
public void update()
}
/**
* 具体通知者
*/
public class ConcreteSubject implements Subject {
private List<Observer> list;
private String state;
public ConcreteSubject() {
list = new ArrayList<Observer>();
}
@Override
public void attach(Observer o) {
list.add(o);
}
@Override
public void detach(Observer o) {
if (!list.isEmpty()) {
list.remove(o);
}
}
@Override
public void notifyObserver() {
for (Observer o : list) {
o.update(message);
}
}
public void setState(String s) {
this.state = s;
System.out.println("更新状态: " + s);
// 消息更新,通知所有观察者
notifyObserver();
}
}
/**
* 具体观察者
*/
public class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update() {
System.out.println(name + " 状态更新了");
}
}