目录
观察者模式的定义
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
观察者模式的实现
观察者模式角色
- 主题角色(Subject):也称为被观察者或可观察者,它是具有状态的对象,并维护着一个观察者列表。主题提供了添加、删除和通知观察者的方法。这个角色可以是接口,也可以是抽象类或者具体的类,因为很多情况下会与其他的模式混用,所以使用抽象类的情况比较多。
- 具体主题角色(Concrete Subject):具体主题是主题的具体实现类。它维护着观察者列表,并在状态发生改变时通知观察者。同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
- 观察者角色(Observer):观察者是接收主题通知的对象。观察者需要实现一个更新方法,当收到主题的通知时,调用该方法进行更新操作。
- 具体观察者角色(Concrete Observer):具体观察者是观察者的具体实现类。它实现了更新方法,定义了在收到主题通知时需要执行的具体操作。存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致。
观察者模式类图
观察者模式代码实现
主题角色
package com.common.demo.pattern.observer;
import java.util.Vector;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 主题角色
* @date 2023/08/07 10:37:05
*/
public abstract class Subject {
private Vector<Observer> obs = new Vector();
public void addObserver(Observer obs) {
this.obs.add(obs);
}
public void delObserver(Observer obs) {
this.obs.remove(obs);
}
protected void notifyObserver() {
for (Observer o : obs) {
o.update();
}
}
public abstract void doSomething();
}
具体主题角色
package com.common.demo.pattern.observer;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 具体主题角色
* @date 2023/08/07 10:39:23
*/
public class ConcreteSubject extends Subject{
@Override
public void doSomething(){
System.out.println("被观察者事件发生改变");
this.notifyObserver();
}
}
观察者角色
package com.common.demo.pattern.observer;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 观察者角色 观察者接口
* @date 2023/08/07 10:30:26
*/
public interface Observer {
void update();
}
具体观察者角色
package com.common.demo.pattern.observer;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 具体观察者角色 观察者角色A
* @date 2023/08/07 10:40:54
*/
public class ConcreteObserverA implements Observer{
@Override
public void update() {
System.out.println("观察者A收到信息,并进行业务处理");
}
}
package com.common.demo.pattern.observer;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 具体观察者角色 观察者角色B
* @date 2023/08/07 10:40:54
*/
public class ConcreteObserverB implements Observer{
@Override
public void update() {
System.out.println("观察者B收到信息,并进行业务处理");
}
}
测试类
package com.common.demo.pattern.observer;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 测试类
* @date 2023/08/07 10:46:55
*/
public class ClientTest {
public static void main(String[] args) {
Subject sub = new ConcreteSubject();
sub.addObserver(new ConcreteObserverA());
sub.addObserver(new ConcreteObserverB());
sub.doSomething();
}
}
测试截图
观察者模式的特点
优点
- 实现了松耦合:观察者模式可以将被观察者和观察者之间的耦合度降低,使得它们可以独立地进行扩展和修改。
- 支持广播通信:建立一套广播通信触发机制,被观察者可以同时通知多个观察者,从而支持广播通信的需求。
- 符合开闭原则:新增或删除观察者不会影响到被观察者和其他观察者的代码,符合开闭原则的要求。
缺点
- 观察者过多可能导致性能问题:如果观察者过多或者观察者的处理逻辑复杂,会影响到系统的性能,花费较多的时间。
- 观察者和被观察者直接关联:在一些情况下,观察者和被观察者之间的直接关联可能会导致设计上的困扰。
- 观察者和观察目标循环依赖:在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者对所观察的目标对象黑盒操作:无相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景
- 当一个对象的改变需要通知其他对象,并且不希望将对象之间的耦合度过高时,可以考虑使用观察者模式。
- 当某个对象的状态改变需要引起一系列相关对象的更新时,不需要知道这些对象是谁,不需知道具体有多少对象有待改变,可以使用观察者模式。
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
注意事项
- 注意观察者和被观察者的关联方式:可以通过接口或抽象类定义观察者接口,使得被观察者只与接口进行交互,而不依赖于具体的观察者实现类。
- 避免循环依赖:观察者和被观察者之间应该避免出现循环依赖的情况,否则可能导致无限循环的通知。
- 如果顺序执行,某一观察者错误会导致系统卡壳,可采用异步方式进行通知。
实际应用
- 网络订阅服务:订阅者可以订阅感兴趣的内容,当内容更新时,订阅者会收到通知。
- 消息中间件:多个消息消费者可以同时监听一个消息主题,当主题发布消息时,所有消费者都会接收到通知并处理消息。
- GUI界面组件:GUI界面中的事件监听机制就是一种观察者模式的实现。
更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)