观察者模式和发布订阅模式都是常用的设计模式,它们的区别主要有以下几点:观察者模式是一对多的关系,发布者和订阅者直接交互,发布者知道订阅者是谁,订阅者依赖于发布者的状态变化;而发布订阅模式是多对多的关系,发布者和订阅者通过一个事件通道交互,发布者不知道订阅者是谁,订阅者可以订阅多个不同的事件,实现松耦合。,,观察者模式多用于单个应用内部,发布订阅模式多用于跨应用的场景,比如消息中间件。
在软件开发中,设计模式是一种被广泛接受并证明有效的解决问题的方法,它们提供了一种可重用的解决方案,可以帮助开发者更快速、更高效地构建软件系统,本文将重点介绍观察者模式(Observer Pattern),这是一种非常实用的设计模式,它可以帮助我们实现解耦和事件驱动。
观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新,这种模式可以让我们将数据的变化与业务逻辑解耦,使得代码更加模块化和可维护。
观察者模式的核心组件有两个:主题(Subject)和观察者(Observer)。
1、主题(Subject):主题是一个拥有多个观察者的类,它负责维护观察者列表,并在状态发生变化时通知所有的观察者,主题可以看作是数据的容器,它持有数据并负责数据的发布。
2、观察者(Observer):观察者是一个实现了特定接口的对象,它需要在收到主题的通知后执行相应的操作,观察者可以看作是对数据变化的反应,当它收到通知时,会根据通知的内容更新自己的状态。
观察者模式有三种主要的角色:
1、具体观察者(Concrete Observer):具体观察者实现了观察者接口,并提供了具体的更新策略,当主题通知观察者某个数据发生了变化时,具体观察者可以根据这个变化来执行特定的操作,如更新UI、记录日志等。
2、抽象观察者(Abstract Observer):抽象观察者实现了观察者接口,但没有提供具体的更新策略,它需要被具体观察者继承并实现更新策略,这样一来,具体观察者只需要关注自己的更新策略,而不需要关心其他的具体实现细节。
3、主题接口(Subject Interface):主题接口定义了添加、删除和通知观察者的方法,具体主题需要实现这个接口,以便能够正确地管理观察者列表并在状态发生变化时通知它们。
下面我们通过一个简单的例子来说明如何使用观察者模式:
假设我们有一个在线商城系统,系统中的商品有价格、库存等属性,当商品的价格或库存发生变化时,我们需要通知相关的用户界面进行更新,为了实现这个功能,我们可以使用观察者模式来解耦数据的变化和业务逻辑。
我们定义一个商品类(Product),它包含价格、库存等属性,以及添加、删除和通知观察者的方法:
public class Product { private List<Observer> observers = new ArrayList<>(); private double price; private int stock; public void addObserver(Observer observer) { observers.add(observer); } public void removeObserver(Observer observer) { observers.remove(observer); } public void notifyObservers() { for (Observer observer : observers) { observer.update(); } } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; notifyObservers(); } public int getStock() { return stock; } public void setStock(int stock) { this.stock = stock; notifyObservers(); } }
我们定义一个抽象观察者类(ConcreteObserver),它实现了观察者接口,并提供了具体的更新策略:
public abstract class ConcreteObserver implements Observer { private String name; public ConcreteObserver(String name) { this.name = name; } @Override public void update() { System.out.println("产品" + name + "的价格或库存发生了变化"); } }
我们定义一个具体的观察者类(User),它继承自抽象观察者类,并实现了具体的更新策略:用户界面需要在收到通知后刷新显示:
public class User extends ConcreteObserver { public User() { super("用户"); } }