小侃设计模式(十八)-发布订阅模式

1.概述

发布订阅模式又叫观察者模式(Observer Pattern),它是指对象之间一对多的依赖关系,每当那个特定对象改变状态时,所有依赖于它的对象都会得到通知并被自动更新,它是行为型模式的一种。观察者模式内部有一个“主题”对象和若干个“观察者”对象,“主题对象”和“观察者”对象是一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。本文将详述观察者模式的原理及使用方式。

2.原理及使用

2.1 原理

观察者模式UML类图如下:
在这里插入图片描述

类图中包含的核心角色有:Subject(抽象被观察者)、ConcreteSubject(具体被观察者)、Observer(抽象观察者)、ObserverA、ObserverB、ObserverC(具体观察者),详细解释如下:

Subject(抽象被观察者): 它定义了一个集合,存储所有的观察者,且对外提供添加和删除观察者的接口;
ConcreteSubject(具体被观察者):具体角色将有关状态存入具体观察者对象,当具体主题的内部状态发生改变时,会给所有注册过的观察者发送通知;
Observer(抽象观察者):观察者抽象类,它定义了一个更新接口,使得在得到主题更改时,更新自身数据;
ObserverA(具体观察者):具体观察者,实现抽象观察者定义的更新接口,以便在主题更新时更新自身的状态。

2.2 案例

小王喜欢炒股,但他是个工薪族,白天还需要上班,他又不能辞职全职炒股(因为还有老婆孩子要养),因此他想到一个好办法,找一个股神帮助自己炒股,股神会根据行情告诉你什么时候买入、什么时候卖出,股神每年会收一定费用。

分析:上述案例中,股神就是典型的被观察者,小王就是典型的观察者,一旦观察到股神给他发的信息,就执行买入卖出动作,股神负责通知小王这种观察者。编码如下:

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();

    }
}

运行结果如下:
在这里插入图片描述
严格意义上来说,观察者模式与发布订阅模式还有一些区别,观察者模式之间的发布者与订阅者是双向关联的,如下图所示:
在这里插入图片描述

发布订阅模式中的发布者与订阅者的关系如下图所示:

在这里插入图片描述
这里多了一个事件中心,负责存放事件和订阅者关系,完全解耦了发布者和订阅者。发布订阅模式是观察者模式的一种,但是又有部分区别:

1.观察者模式中,发布者与订阅者直接关联,发布者维护观察者列表,发布者状态变更通知订阅者;在发布-订阅模式中,订阅者与发布者相互不了解,通过事件中心进行通信;
2.耦合性方面,发布订阅者中发布者与订阅者完全松耦合;
3.观察者模式主要是以同步的方式来发送消息,发布订阅者一般以异步的方式来实现。

2.3 观察者在JDK源码中的应用

JDK源码中有个Observable类,它就相当于一个Subject,实现了核心方法,包括addObserver()、deleteObserver()、notifyObserver()等,JDK源码中的Observer接口,就是一个订阅者接口,代码如下:
在这里插入图片描述
在这里插入图片描述

2.4 观察者的优点与缺点

2.4.1 优点

1.发布者与观察者是抽象耦合的,
2.发布者和订阅者之间有一套完整的信息发送机制;

2.4.2 缺点

1.观察者与被观察者之间之间关联;
2.若观察者通知出现异常,则可能造成消息发送奔溃;

3.小结

1.观察者模式适用于对象状态发生变化,与之相关的对象需要收到通知并更新自身;
2.观察者模式需要考虑消息异步发送,提升容错率。

4.参考文献

1.《设计模式之禅》-秦小波著
2.《大话设计模式》-程杰著
3.https://www.bilibili.com/video/BV1G4411c7N4-尚硅谷设计模式
4.https://www.runoob.com/design-pattern/observer-pattern.html

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
发布-订阅模式(Publish-Subscribe Pattern)具有以下特点和优势: 1. 解耦性:通过发布-订阅模式,发布者和订阅者之间的关系被解耦。发布者不需要知道谁是订阅者,订阅者也不需要知道谁是发布者。这种解耦性使得系统中的组件可以独立地进行修改、扩展和重用。 2. 异步通信:发布-订阅模式通常采用异步通信方式,即发布者和订阅者之间不需要直接交互。这样可以提高系统的性能和响应速度,因为发布者不需要等待所有订阅者都处理完消息后才能继续执行。 3. 扩展性:发布-订阅模式支持动态添加和移除订阅者,以及新增主题和取消主题订阅的灵活性。这使得系统可以方便地进行扩展和改进,而不需要对已有的组件进行修改。 4. 消息传递机制:发布-订阅模式提供了一种灵活的消息传递机制。发布者可以将消息发送到指定的主题上,而订阅者可以选择订阅感兴趣的主题。这种机制使得系统中的不同组件可以通过消息进行通信,实现松耦合的架构。 5. 可靠性:发布-订阅模式可以提高系统的可靠性。当一个订阅者出现故障或无法处理消息时,不会影响其他订阅者的正常运行。系统可以容错地处理故障,确保消息的可靠传递。 6. 多对多通信:发布-订阅模式支持多对多的通信。一个发布者可以有多个订阅者,一个订阅者也可以订阅多个主题。这种多对多的通信方式能够满足复杂系统中不同组件之间的通信需求。 综上所述,发布-订阅模式具有解耦性、异步通信、扩展性、消息传递机制、可靠性和多对多通信等特点和优势,适用于需要实现解耦和异步通信的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值