行为模式 - 发布订阅模式:
发布订阅模式原理:
发布订阅模式又叫观察者模式(Observer Pattern),它是指对象之间一对多的依赖关系,每当那个特定对象改变状态时,所有依赖于它的对象都会得到通知并被自动更新,它是行为型模式的一种。观察者模式内部有一个“主题”对象和若干个“观察者”对象,“主题对象”和“观察者”对象是一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。本文将详述观察者模式的原理及使用。
类图中包含的核心角色有:Subject(抽象被观察者)、ConcreteSubject(具体被观察者)、Observer(抽象观察者)、ObserverA、ObserverB、ObserverC(具体观察者),详细解释如下:
- Subject(抽象被观察者): 它定义了一个集合,存储所有的观察者,且对外提供添加和删除观察者的接口;
- ConcreteSubject(具体被观察者):具体角色将有关状态存入具体观察者对象,当具体主题的内部状态发生改变时,会给所有注册过的观察者发送通知;
- Observer(抽象观察者):观察者抽象类,它定义了一个更新接口,使得在得到主题更改时,更新自身数据;
- ObserverA(具体观察者):具体观察者,实现抽象观察者定义的更新接口,以便在主题更新时更新自身的状态。
使用案例分析:
小王喜欢炒股,但他是个工薪族,白天还需要上班,他又不能辞职全职炒股(因为还有老婆孩子要养),因此他想到一个好办法,找一个股神帮助自己炒股,股神会根据行情告诉你什么时候买入、什么时候卖出,股神每年会收一定费用。
java
public abstract class Observer {
public String name;
public StockManager stockManager;
public abstract void buy(Stock stock);
public abstract void sale(Stock stock);
}
@Data
public class Stock {
/**
* 股票名称
*/
private String name;
/**
* 买入或卖出数量
*/
private Integer num;
/**
* 买入或卖出价格
*/
private Double price;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StockManager {
private List<Observer> lists = new ArrayList<>();
public StockManager(String name) {
this.name = name;
}
private String name;
private Stock stock;
public void notifyAllObserversBuy() {
lists.forEach(list -> {
System.out.println("通知:" + list.name);
list.buy(stock);
});
}
public void notifyAllObserversSale() {
lists.forEach(list -> {
System.out.println("通知:" + list.name);
list.sale(stock);
});
}
public void add(Observer observer) {
lists.add(observer);
System.out.println("添加新的投资客户:" + observer.name);
}
public void remove(Observer observer) {
lists.remove(observer);
System.out.println("删除老的投资客户:" + observer.name);
}
}
public class WangObserver extends Observer {
public WangObserver(StockManager stockManager, String name) {
this.stockManager = stockManager;
this.name = name;
}
@Override
public void buy(Stock stock) {
System.out.println(name + "购买股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());
}
@Override
public void sale(Stock stock) {
System.out.println(name + "卖出股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());
}
}
public class ZhangObserver extends Observer {
public ZhangObserver(StockManager stockManager, String name) {
this.stockManager = stockManager;
this.name = name;
}
@Override
public void buy(Stock stock) {
System.out.println(name + "购买股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());
}
@Override
public void sale(Stock stock) {
System.out.println(name + "卖出股票:" + stock.getName() + ",成交价格:" + stock.getPrice() + ",成交数量:" + stock.getNum());
}
}
public class Client {
public static void main(String[] args) {
StockManager stockManager = new StockManager("巴菲特");
ZhangObserver zhangObserver = new ZhangObserver(stockManager, "小张");
WangObserver wangObserver = new WangObserver(stockManager, "小王");
stockManager.add(zhangObserver);
stockManager.add(wangObserver);
Stock stock = new Stock();
stock.setName("贵州茅台");
stock.setNum(1000);
stock.setPrice(1589.0);
stockManager.setStock(stock);
stockManager.notifyAllObserversBuy();
System.out.println("-------------------------");
stock.setPrice(1899.0);
stockManager.notifyAllObserversSale();
}
}
补充信息:
严格意义上来说,观察者模式与发布订阅模式还有一些区别,观察者模式之间的发布者与订阅者是双向关联的,如下图所示:
发布订阅模式中的发布者与订阅者的关系如下图所示:
这里多了一个事件中心,负责存放事件和订阅者关系,完全解耦了发布者和订阅者。发布订阅模式是观察者模式的一种,但是又有部分区别:
- 观察者模式中,发布者与订阅者直接关联,发布者维护观察者列表,发布者状态变更通知订阅者;在发布-订阅模式中,订阅者与发布者相互不了解,通过事件中心进行通信;
- 耦合性方面,发布订阅者中发布者与订阅者完全松耦合;
- 观察者模式主要是以同步的方式来发送消息,发布订阅者一般以异步的方式来实现。