哇塞码农设计模式系列 -- 观察者模式&事件委托模式

更新于2024-11-05 08:01:0012 分钟5 千字3281766800
摘要

观察者模式

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,其所有依赖者都会收到通知并自动更新。观察者模式也被称为发布-订阅(Publish-Subscribe)模式。

在观察者模式中,有以下几个角色:

  1. Subject(主题):定义了一个接口,用于添加、删除和通知观察者对象。当主题的状态发生变化时,会通知所有的观察者对象。
  2. ConcreteSubject(具体主题):实现了 Subject 接口,维护了一个观察者列表,并在状态发生变化时通知观察者。
  3. Observer(观察者):定义了一个更新接口,用于接收主题的通知并更新自身状态。
  4. ConcreteObserver(具体观察者):实现了 Observer 接口,当接收到主题的通知时,会根据通知更新自身状态。

UML类图

PlantUML Image

Java示例

import java.util.ArrayList;
import java.util.List;

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

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

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

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

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

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

    // 某些操作导致状态变化,通知观察者
    public void doSomething() {
        // 执行一些操作
        String message = "Something has happened!";
        notifyObservers(message);
    }
}

// 具体观察者类
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

// 测试类
public class ObserverPatternExample {
    public static void main(String[] args) {
        // 创建具体主题对象
        ConcreteSubject subject = new ConcreteSubject();

        // 创建具体观察者对象
        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

        // 注册观察者
        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        // 主题对象执行某些操作,观察者收到通知
        subject.doSomething();

        // 移除观察者
        subject.removeObserver(observer2);

        // 再次执行某些操作,只有一个观察者收到通知
        subject.doSomething();
    }
}

适用场景

观察者模式在以下场景中特别适用:

  1. 对象间存在一对多的依赖关系:当一个对象的状态发生变化时,需要通知多个其他对象进行相应的更新操作。观察者模式能够很好地解决这种一对多的依赖关系。
  2. 解耦观察者和主题:观察者模式可以使主题和观察者之间的耦合度降低,使得它们之间可以独立地变化,而不需要相互了解彼此的具体实现细节。
  3. 动态添加/移除观察者:观察者模式允许在运行时动态地添加或移除观察者,而不需要修改主题类的代码,从而使得系统更加灵活。
  4. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时:例如,模型(主题)的状态变化需要通知视图(观察者)进行更新,这种情况下观察者模式很合适。

适用观察者模式的典型场景包括:

  • GUI 编程中的事件处理:例如,按钮点击、鼠标移动等事件的处理通常使用观察者模式。
  • 股票市场报价系统:股票的价格变化会影响到许多观察者,比如股票交易系统、股票分析系统等。
  • 车辆追踪系统:车辆的位置变化会影响到许多观察者,比如地图显示系统、交通监控系统等。

总之,当存在对象之间一对多的依赖关系,且希望在对象状态变化时通知多个其他对象进行更新时,观察者模式是一个非常合适的设计模式。

事件委托模式

观察者模式虽然是一种强大的设计模式,但也存在一些不足之处。以下是观察者模式的一些局限性以及事件委托模式如何弥补这些不足:

1. 强耦合性: 在观察者模式中,观察者和主题之间存在一定的耦合关系。主题需要知道观察者的接口,而观察者需要知道主题的接口。这种紧密的耦合关系可能导致系统的复杂性增加,并且难以维护。

2. 性能问题: 当观察者过多时,通知所有观察者可能会导致性能问题,特别是在大规模系统中。每次状态变化都需要遍历所有观察者进行通知,这可能会造成性能瓶颈。

3. 观察者状态不一致: 如果观察者之间有状态依赖,当观察者状态不一致时可能会导致问题。例如,某些观察者在更新时依赖于其他观察者的状态,但是观察者之间的状态变化不是原子性的,可能会出现状态不一致的情况。

事件委托模式可以在一定程度上弥补观察者模式的不足。事件委托模式是一种基于事件和回调机制的设计模式,它通过将事件处理逻辑委托给特定的处理程序来解耦发送者和接收者之间的依赖关系。在事件委托模式中,发送者不需要直接知道接收者的具体实现,只需要将事件发送给中间件(事件总线),由中间件负责将事件分发给相应的处理程序。

事件委托模式的优点包括:

  • 解耦性强: 发送者和接收者之间解耦,发送者只需要发送事件,而不需要知道接收者的具体实现。
  • 灵活性高: 可以动态地添加或移除事件处理程序,系统更加灵活。
  • 性能高效: 事件委托模式通常能够提供较高的性能,因为事件的分发是通过中间件进行的,而不是直接遍历所有观察者。

尽管事件委托模式具有上述优点,但它也有一些局限性。例如,事件委托模式通常用于单向通信,而观察者模式通常用于双向通信。因此,在选择使用观察者模式还是事件委托模式时,需要根据具体的需求和场景进行权衡和选择。

PlantUML Image

// 事件处理程序接口
interface EventHandler {
    void handle();
}

// 具体事件处理程序类
class ConcreteEventHandler implements EventHandler {
    @Override
    public void handle() {
        // 具体的事件处理逻辑
        System.out.println("Event handled by ConcreteEventHandler");
    }
}

// 发送者类
class Sender {
    private EventHandler eventHandler;

    public void delegate(EventHandler eventHandler) {
        this.eventHandler = eventHandler;
    }

    public void sendEvent() {
        if (eventHandler != null) {
            eventHandler.handle();
        }
    }
}

// 接收者类
class Receiver {
    public void receiveEvent() {
        // 接收并处理事件
        System.out.println("Event received by Receiver");
    }
}

// 测试类
public class EventDelegationExample {
    public static void main(String[] args) {
        // 创建发送者对象
        Sender sender = new Sender();

        // 创建事件处理程序对象
        EventHandler eventHandler = new ConcreteEventHandler();

        // 设置事件处理程序
        sender.delegate(eventHandler);

        // 发送事件
        sender.sendEvent();

        // 创建接收者对象
        Receiver receiver = new Receiver();

        // 发送事件给接收者
        sender.delegate(new EventHandler() {
            @Override
            public void handle() {
                receiver.receiveEvent();
            }
        });

        sender.sendEvent();
    }
}

评论区

你认为这篇文章怎么样?
  • great
    0
  • happy
    0
  • doubt
    0
  • boring
    0
  • bad
    0

0/2048