观察者模式
(Observer Pattern),也称为发布-订阅模式
,允许对象在其状态发生变化
时通知其他对象
。主要用于实现一对多的通信
,例如当一个对象更改状态时,所有依赖于它的对象都会收到通知并自动更新。
核心角色:
主题(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法
。
观察者(Observer):观察者是接收主题通知的对象
。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作
。
具体主题(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表
,并在状态发生改变时通知观察者
。
具体观察者(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法
,定义了在收到主题通知时需要执行的具体操作
优点
观察者模式可以实现松耦合设计,主题和观察者不直接相互引用,耦合度降低。
观察者模式可以很容易地扩展观察者的数量。
缺点
当观察者对象很多时,通知的分发可能会造成性能瓶颈。
如果一个被观察者对象知道所有的观察者对象,可能会导致循环依赖,这样会增加系统的复杂性。
适用场景
当一个对象的改变需要同时改变其他对象时,而其他的这些对象不依赖于主题对象的具体类型时。
当要实现一种事件处理机制时,比如按钮点击事件、鼠标移动事件等。
示例
:
// 观察者接口
public interface Observer {
void update(String message);
}
// 具体观察者
public class ConcreteObserver implements Observer{
private String observerState;
public String getObserverState(){
return observerState;
}
@Override
public void update(String message) {
this.observerState=message;
System.out.println("Observer:" +observerState);
}
}
// 主题接口
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notitfyObservers();
}
// 具体主题
public class ConcreteSubject implements Subject{
private List<Observer> observers=new ArrayList<>();
private String subjectState;
public String getSubjectState(){
return subjectState;
}
public void setSubjectState(String subjectState){
this.subjectState=subjectState;
notitfyObservers();
}
@Override
public void registerObserver(Observer o) {
if (!observers.contains(o)){
observers.add(o);
}
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notitfyObservers() {
for (Observer observer : observers) {
observer.update(subjectState);
}
}
}
public class Client {
public static void main(String[] args) {
// 创建主题和观察者
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver();
ConcreteObserver observer2 = new ConcreteObserver();
// 注册观察者
subject.registerObserver(observer1);
subject.registerObserver(observer2);
// 更改主题状态,观察者将被通知
subject.setSubjectState("New news is available!");
}
}