行为型设计模式:观察者模式

观察者模式(发布订阅模式),在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

现在有一个注册后发送欢迎使用的功能,实现如下:

public class UserService{
  private SendMessageService sendMessageService; // 依赖注入

  public Long register(String telephone, String password) {
    //注册行为
    ...
   //发消息 senMessageService.sendHellow(userId);
return userId; } }

这个接口就干了两件事 注册 发消息,如果一辈子需求不变,这么写是可以的,但是实际并不会一辈子都不变,那怎么办呢?发完消息还要干别的,给送个优惠券,给设置些什么什么权限的,注册成功后可能要做很多事情。这时候观察者模式就有用了,那么重构如下:

首先定义观察者接口,并且定义观察到之后的行为

//Observer是观察员的意思 监视者Register这个行为
public interface RegObserver {

    //handle:处理处理注册成功这个事
    void handleRegSuccess(Long userId);

}

实现观察者行为

public class RegGiveShitObserverImpl implements RegObserver {

    private ShitService shitService;

    @Override
    public void handleRegSuccess(Long userId) {
        //里面实现了送给某人一坨屎
        shitService.sendShit(userId);
    }
}
public class RegWelcomObserverImpl implements RegObserver {

    private SendMessageService sendMessageService;

    @Override
    public void handleRegSuccess(Long userId) {
        //里面实现了欢迎某某人的到来
        sendMessageService.sendMessage(userId);
    }
}

当行为发生的时候,通知观察者

public class UserService {
    private List<RegObserver> regObservers = new ArrayList<>();

    //将观察者需要执行的行为于执行被观察者前设置
    public void setRegObservers(List<RegObserver> observers) {
        regObservers.addAll(observers);
    }

    public Long register(String telephone, String password) {
        //注册行为
        ...

     //通知观察者
for (RegObserver observer : regObservers) { observer.handleRegSuccess(userId); } return userId; } }

当有新的观察者行为出现时,只需要定义新的观察者实现类并实现行为,在使用前通过 setRegObservers() 加入进行为列表即可,注册用户类是不会进行修改的,对修改关闭,对新增开放。

Google Guava EventBus

我们知道,框架的作用:隐藏实现细节,降低开发难度,做到代码复用,解耦业务与非业务代码,让程序员聚焦业务开发。

Google Guava EventBus 就是一个比较著名的 EventBus 框架,它不仅仅支持异步非阻塞模式,同时也支持同步阻塞模式。

那么以上的代码如何通过Google Guava EventBus实现呢,我们接着往下看:

两个监听实现类的修改:

public class RegWelcomeObserverImpl implements RegObserver {

    private SendMessageService sendMessageService;

    @Override
    @Subscribe
    public void handleRegSuccess(Long userId) {
        //里面实现了欢迎某某人的到来
        sendMessageService.sendMessage(userId);
    }
}
public class RegGiveShitObserverImpl implements RegObserver {

    private ShitService shitService;

    @Override
    @Subscribe
    public void handleRegSuccess(Long userId) {
        //里面实现了送给某人一坨屎
        shitService.sendShit(userId);
    }
}

被监听类(注册用户的修改)

public class UserService {

    private EventBus eventBus;

    private static final int DEFAULT_EVENTBUS_THREAD_POOL_SIZE = 20;

    public UserService() {
        //这么写就是同步阻塞模式
        eventBus = new EventBus();
        //这么写就是异步非阻塞模式
        eventBus = new AsyncEventBus(Executors.newFixedThreadPool(DEFAULT_EVENTBUS_THREAD_POOL_SIZE));
    }

    public void setRegObservers(List<RegObserver> observers) {
     //注册监听事件 observers.forEach(observer
-> eventBus.register(observer)); } public Long register(String telephone, String password) { //注册行为 ... Long userId = 123456L; //发布一个事件 eventBus.post(userId); return userId; } }

 

当然你也可以使用完全不同的两个类去做实现,比如:

public class ObserverA{
  @Subscribe  public void doA(A a) { //do something ... } } public class ObserverB{   @Subscribe public void doB(B b) { //do something ... }
   @Subscribe
  public void doC(C c) { //do something ... }
}

 在调用时,根据类型触发指定的行为:

public class test{

 public void doSometing(){
   
  private ObserverA observerA = new ObserverA();  
  private ObserverB observerB = new ObserverB();
    
  EventBus eventBus = new EventBus();  
    
  //注册观察者  
  eventBus.register(observerA);
  eventBus.register(observerB);

  //发布事件 
  eventBus.post(new A());
  eventBus.post(new B());
  eventBus.post(new C());
} } 

 EventBus中有两个主要函数register()、post()的实现原理图如下:

 

 

 

 

 

 

从图中我们可以看出,最关键的一个数据结构是 Observer 注册表,记录了消息类型和可接收消息函数的对应关系。

当调用 register() 函数注册观察者的时候,EventBus 通过解析 @Subscribe 注解,生成 Observer 注册表。

当调用 post() 函数发送消息的时候,EventBus 通过注册表找到相应的可接收消息的函数,然后通过 Java 的反射语法来动态地创建对象、执行函数。

对于同步阻塞模式,EventBus 在一个线程内依次执行相应的函数。

对于异步非阻塞模式,EventBus 通过一个线程池来执行相应的函数。

posted @ 2022-04-08 09:02  皮肤黝黑的小白  阅读(27)  评论(0编辑  收藏  举报