A类的数据变化需要通知B类、甚至通知D类,可以使用观察者模式
实际开发中,一般需要结合单列模式一起使用。
首先定义了Observer接口,它规定了观察者必须实现update方法,用于接收主题发送的消息并进行相应处理。
interface Observer {
void update(String message);
}ConcreteObserver类实现了Observer接口,每个具体观察者有一个名称name。在构造函数中,可以根据autoRegister参数决定是否自动将自身注册到单例主题中。当接收到更新消息时,会在控制台打印出自身名称和接收到的消息内容。
class ConcreteObserver implements Observer {
private final String name;
public ConcreteObserver(String name, boolean autoRegister) {
this.name = name;
if (autoRegister) {
SingletonSubject.getInstance().addObserver(this);
}
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}SingletonSubject类是整个模式的核心枢纽。它采用静态内部类Holder来确保单例实例的创建,这种方式既保证了线程安全又实现了延迟加载。
private static class Holder {
private static final SingletonSubject INSTANCE = new SingletonSubject();
}其私有构造函数防止外部直接实例化,只能通过getInstance方法获取单例对象。
private SingletonSubject() {}
public static SingletonSubject getInstance() {
return Holder.INSTANCE;
}它维护了一个CopyOnWriteArrayList类型的观察者列表,这种数据结构在多线程环境下能够保证安全地添加和移除观察者,同时在遍历通知观察者时也不会抛出ConcurrentModificationException。提供了添加、移除观察者以及通知所有观察者的方法。
private final List<Observer> observers = new CopyOnWriteArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}静态内部类单例模式确保了主题对象在整个应用程序中只有一个实例存在,避免了因创建多个主题对象而导致的资源浪费,如内存占用和初始化开销等。并且只有在首次访问单例实例时才会创建,实现了延迟加载,对于资源敏感型应用非常关键。
观察者模式使得主题与观察者之间呈现松耦合关系。主题不需要了解观察者的具体细节,只负责维护观察者列表并在状态变化时通知它们。观察者也只需关注自身对主题消息的处理逻辑,而无需关心主题的内部实现。这种松耦合结构使得系统具有极高的可扩展性,无论是添加新的观察者还是修改主题或观察者的行为,都不会对其他部分产生过大的影响,方便系统的迭代和升级。
通过使用CopyOnWriteArrayList作为观察者列表,在多线程环境下能够安全地进行观察者的添加、移除和通知操作。当一个线程在遍历通知观察者时,即使其他线程对观察者列表进行了修改(添加或移除观察者),也不会影响当前遍历的稳定性,有效避免了并发问题,确保系统在多线程场景下的正确运行。
示例代码
package pattern;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
// 定义观察者接口
interface Observer {
void update(String message);
}
// 具体观察者实现
class ConcreteObserver implements Observer {
private final String name;
public ConcreteObserver(String name, boolean autoRegister) {
this.name = name;
if (autoRegister) {
SingletonSubject.getInstance().addObserver(this);
}
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
// 单例的主题类(Subject)
class SingletonSubject {
// 静态内部类,用于创建单例实例
private static class Holder {
private static final SingletonSubject INSTANCE = new SingletonSubject();
}
// 私有构造函数,防止外部直接实例化
private SingletonSubject() {}
// 获取单例实例的方法
public static SingletonSubject getInstance() {
return Holder.INSTANCE;
}
// 使用线程安全的集合
private final List<Observer> observers = new CopyOnWriteArrayList<>();
// 添加观察者
public void addObserver(Observer observer) {
observers.add(observer);
}
// 移除观察者
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// 通知所有观察者
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
// 测试类
public class Main {
public static void main(String[] args) {
// 创建观察者
ConcreteObserver observer1 = new ConcreteObserver("Observer1",true);
ConcreteObserver observer2 = new ConcreteObserver("Observer2",true);
// 通知观察者
SingletonSubject.getInstance().notifyObservers("Hello Observers!");
// 移除一个观察者并再次通知
SingletonSubject.getInstance().removeObserver(observer1);
SingletonSubject.getInstance().notifyObservers("Observer 1 is removed.");
}
}在消息推送系统中,如移动应用的推送服务或网站的实时消息推送。可以将消息源作为单例主题,各个接收消息的客户端或模块作为观察者。当有新消息产生时,单例主题将消息推送给所有注册的观察者,实现消息的广播式分发,确保各个相关部分能够及时获取并处理消息。
对于一个复杂系统的状态监控,例如服务器集群的监控系统。可以将系统状态信息收集模块作为单例主题,而各种监控指标处理模块(如 CPU 使用率监控、内存使用量监控等)作为观察者。当系统状态发生变化时,主题收集到最新状态信息并通知所有观察者,观察者根据自身职责对状态信息进行分析、记录或发出警报等操作,从而实现对整个系统状态的全面监控和及时响应。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。