返回

观察者模式与发布/订阅模式的差异分析及代码实现

前端

概念

观察者模式

观察者模式是一种软件设计模式,它定义了一种一对多的依赖关系,其中一个对象(称为“主题”)可以通知多个对象(称为“观察者”)它的状态或事件的变化。当主题的状态或事件发生变化时,它会自动通知所有观察者,以便它们可以相应地更新自己。

发布/订阅模式

发布/订阅模式是一种软件设计模式,它定义了一种一对多的通信机制,其中一个对象(称为“发布者”)可以将消息发送给多个对象(称为“订阅者”),而无需知道订阅者的具体身份或数量。发布者只负责将消息发送给中间媒介(称为“消息代理”),而订阅者只需要向消息代理注册自己的兴趣,即可收到相关消息。

场景

观察者模式通常用于以下场景:

  • 当一个对象的状态或事件发生变化时,需要通知多个其他对象。
  • 当需要在多个对象之间建立松耦合的关系时。
  • 当需要在系统中实现可扩展性和灵活性时。

发布/订阅模式通常用于以下场景:

  • 当需要在多个对象之间建立松耦合的关系时。
  • 当需要在系统中实现可扩展性和灵活性时。
  • 当需要将消息从一个对象发送到多个对象,而无需知道接收者的具体身份或数量时。

优缺点比较

特性 观察者模式 发布/订阅模式
耦合性 中等 松散
可扩展性 良好 优秀
灵活性 良好 优秀
性能 良好 优秀
易用性 适中 容易
场景 当需要在多个对象之间建立松耦合的关系时。 当需要将消息从一个对象发送到多个对象,而无需知道接收者的具体身份或数量时。

实现思路

观察者模式

观察者模式的实现思路如下:

  1. 定义一个抽象主题类,该类负责管理观察者列表。
  2. 定义一个抽象观察者类,该类定义了更新方法,用于接收主题的状态或事件变化通知。
  3. 定义具体主题类,继承抽象主题类,并实现其方法。
  4. 定义具体观察者类,继承抽象观察者类,并实现其方法。
  5. 将具体观察者添加到具体主题的观察者列表中。
  6. 当主题的状态或事件发生变化时,通知所有观察者。

发布/订阅模式

发布/订阅模式的实现思路如下:

  1. 定义一个消息代理类,该类负责管理发布者和订阅者列表。
  2. 定义一个发布者类,该类负责向消息代理发送消息。
  3. 定义一个订阅者类,该类负责向消息代理注册自己的兴趣,并接收相关消息。
  4. 当发布者向消息代理发送消息时,消息代理将消息发送给所有订阅者。

代码示例

观察者模式

// 主题接口
interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }

    // 其他方法...
}

// 观察者接口
interface Observer {
    void update();
}

// 具体观察者类
class ConcreteObserver1 implements Observer {
    @Override
    public void update() {
        // 具体更新逻辑...
    }
}

class ConcreteObserver2 implements Observer {
    @Override
    public void update() {
        // 具体更新逻辑...
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer observer1 = new ConcreteObserver1();
        Observer observer2 = new ConcreteObserver2();

        subject.addObserver(observer1);
        subject.addObserver(observer2);

        subject.notifyObservers();
    }
}

发布/订阅模式

// 消息代理类
class MessageBroker {
    private Map<String, List<Subscriber>> subscribers = new HashMap<>();

    public void publish(String topic, Message message) {
        List<Subscriber> subscribers = this.subscribers.get(topic);
        if (subscribers != null) {
            for (Subscriber subscriber : subscribers) {
                subscriber.receive(message);
            }
        }
    }

    public void subscribe(String topic, Subscriber subscriber) {
        List<Subscriber> subscribers = this.subscribers.get(topic);
        if (subscribers == null) {
            subscribers = new ArrayList<>();
            this.subscribers.put(topic, subscribers);
        }
        subscribers.add(subscriber);
    }

    public void unsubscribe(String topic, Subscriber subscriber) {
        List<Subscriber> subscribers = this.subscribers.get(topic);
        if (subscribers != null) {
            subscribers.remove(subscriber);
        }
    }
}

// 发布者类
class Publisher {
    private MessageBroker messageBroker;

    public Publisher(MessageBroker messageBroker) {
        this.messageBroker = messageBroker;
    }

    public void publish(String topic, Message message) {
        messageBroker.publish(topic, message);
    }
}

// 订阅者类
class Subscriber {
    private String topic;

    public Subscriber(String topic) {
        this.topic = topic;
    }

    public void receive(Message message) {
        // 具体处理逻辑...
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        MessageBroker messageBroker = new MessageBroker();
        Publisher publisher = new Publisher(messageBroker);
        Subscriber subscriber1 = new Subscriber("topic1");
        Subscriber subscriber2 = new Subscriber("topic2");

        messageBroker.subscribe("topic1", subscriber1);
        messageBroker.subscribe("topic2", subscriber2);

        publisher.publish("topic1", new Message("Hello, world!"));
        publisher.publish("topic2", new Message("Goodbye, world!"));
    }
}

实际用法

观察者模式和发布/订阅模式都是非常有用的设计模式,它们在许多实际应用中都有着广泛的应用。以下是一些实际用法示例:

  • 观察者模式:
    • GUI编程:观察者模式可以用来实现GUI组件之间的通信,当一个GUI组件发生变化时,其他GUI组件可以自动更新。
    • 事件处理:观察者模式可以用来实现事件处理,当一个事件发生时,可以通知所有感兴趣的事件处理程序。
    • 状态管理:观察者模式可以用来实现状态管理,当一个对象的状态发生变化时,可以通知所有感兴趣的对象。
  • 发布/订阅模式:
    • 消息传递:发布/订阅模式可以用来实现消息传递,发布者可以将消息发送给所有订阅者,而无需知道订阅者的具体身份或数量。
    • 事件处理:发布/订阅模式可以用来实现事件处理,当一个事件发生时,可以通知所有感兴趣的事件处理程序。
    • 负载均衡:发布/订阅模式可以用来实现负载均衡,将任务分配给多个工作者节点。

总结

观察者模式和发布/订阅模式都是非常有用的设计模式,它们都有各自的优缺点和适用场景。在实际应用中,需要根据具体情况选择合适的模式。