Bootstrap

设计模式使用场景实现示例及优缺点(行为型模式——观察者模式)

观察者模式(Observer Pattern)

观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。
观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

核心组件

  • Subject(主题):主题保存了一组观察者,提供用于增加或删除观察者的接口。
  • Observer(观察者):为那些在主题状态改变时需要获得通知的对象定义一个更新接口。
  • ConcreteSubject(具体主题):存储具体观察者关心的数据,发送通知给观察者,通常包含对具体数据的增删改操作。
  • ConcreteObserver(具体观察者):实现观察者接口,以便在得到通知时更新自身。

适用场景

  1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时
    • 观察者模式允许你独立地扩展或复用核心功能。
  2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时
    • 观察者模式可以让你在不修改这些类的前提下增加新的观察者。
  3. 当一个对象必须通知其他对象,但你希望避免做成这些对象之间的紧密耦合时
    • 观察者模式提供了一种松耦合的设计解决方案。

实现实例

以新闻应用为例,其中新闻发布系统(主题)需要通知所有订阅者(观察者)新闻更新。

主题接口(Subject Interface)

定义了附加和删除观察者的方法,以及通知观察者的方法。

public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

具体主题(Concrete Subject)

存储状态,并在状态改变时通知观察者。

public class NewsAgency implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String news;

    public void registerObserver(Observer o) {
        observers.add(o);
    }

    public void removeObserver(Observer o) {
        observers.remove(o);
    }

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

    public void setNews(String news) {
        this.news = news;
        notifyObservers();
    }
}

观察者接口(Observer Interface)

定义更新接口,用于获取状态改变通知。

public interface Observer {
    void update(String news);
}

具体观察者(Concrete Observer)

实现观察者接口,根据通知更新自己。

public class NewsChannel implements Observer {
    private String news;

    @Override
    public void update(String news) {
        this.news = news;
        System.out.println("News Updated: " + news);
    }
}

客户端代码(Client Code)

演示如何使用观察者模式。

public class Client {
    public static void main(String[] args) {
        NewsAgency newsAgency = new NewsAgency();
        NewsChannel channel = new NewsChannel();

        newsAgency.registerObserver(channel);
        newsAgency.setNews("New update on AI technology!");
    }
}

优缺点

优点
  1. 支持广播通信
    • 观察者模式提供了一种订阅机制,可以实现消息的广播。
  2. 应用松耦合
    • 主题与观察者之间使用抽象耦合,可以轻松地添加新的观察者。
缺点
  1. 可能引发无序的更新
    • 如果观察者的更新方法引发循环依赖,可能导致系统行为难以预测。
  2. 当观察者和主题之间的依赖关系复杂时,可能需要额外的维护成本

类图

+----------------+         +------------------+
|   Subject      |-------->|   Observer       |
+----------------+         +------------------+
| + registerObserver()     | + update()       |
| + removeObserver()       |                  |
| + notifyObservers()      +------------------+
+----------------+         |
|                |         |
+----------------+         |
                           |
      +-------------------+--------+----------------+
      |                   |                 |                |
+---------------+ +-----------------+ +----------------+ +--------------+
|ConcreteSubject| |ConcreteObserver1| |ConcreteObserver2| | ...          |
+---------------+ +-----------------+ +----------------+ +--------------+
| + setNews()   | | + update()       | | + update()      | | + update()   |
+---------------+ +-----------------+ +----------------+ +--------------+

总结

观察者模式提供了一种优雅的方式来实现对象间的通信,特别适用于状态变化需要通知多个对象的场景。通过将主题与观察者解耦,增加了系统的灵活性和可扩展性,同时也需注意避免循环依赖和更新顺序问题。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;