设计模式之美学习-行为型-观察者模式(二十六)

什么是观察者模式

在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知,被依赖对象为被观察者,依赖对象为观察者

在实际开发中有多种叫法::Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener

设计模式其实要干的事情就是解耦。创建型模式是将创建和使用代码解耦,结构型模式是将不同功能代码解耦,行为型模式是将不同的行为代码解耦,具体到观察者模式,它是将观察者和被观察者代码解耦。借助设计模式,我们利用更好的代码结构,将一大坨代码拆分成职责更单一的小类,让其满足开闭原则、高内聚松耦合等特性,以此来控制和应对代码的复杂性,提高代码的可扩展性

常见的应用方式

/**
 * 定义观察者接口
 */
public interface Subject {
    //注册观察者
    void registerObserver(Observer observer);
    //删除观察者
    void removeObserver(Observer observer);
    //发起通知
    void notifyObservers(Message message);
}

/**
 * 定义被观察者接口
 */
public interface Observer {
    void update(Message message);
}

public class ConcreteSubject implements Subject {
    //存储被观察者
    private List<Observer> observers = new ArrayList<Observer>();

    //注册
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
   //删除
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
   //发起通知
    @Override
    public void notifyObservers(Message message) {
        //循环调用被观察者通知方法
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

}

//被观察者实现1
public class ConcreteObserverOne implements Observer {
    //接收通知
    @Override
    public void update(Message message) {
        //TODO: 获取消息通知,执行自己的逻辑...
        System.out.println("ConcreteObserverOne is notified.");
    }
}

//被观察者实现
public class ConcreteObserverTwo implements Observer {
    //接收通知
    @Override
    public void update(Message message) {
        //TODO: 获取消息通知,执行自己的逻辑...
        System.out.println("ConcreteObserverTwo is notified.");
    }
}

public class Demo {
    public static void main(String[] args) {
        //创建一个观察者对象
        ConcreteSubject subject = new ConcreteSubject();
        //注册被观察者
        subject.registerObserver(new ConcreteObserverOne());
        subject.registerObserver(new ConcreteObserverTwo());
        //发起通知
        subject.notifyObservers(new Message());
    }
}

注册场景应用

需求

假设我们在开发一个 P2P 投资理财系统,用户注册成功之后,我们会给用户发放投资体验金。代码实现大致是下面这个样子的

原始代码

public class UserController {
    private UserService userService; // 依赖注入
    private PromotionService promotionService; // 依赖注入

    public Long register(String telephone, String password) {
        //省略输入参数的校验代码
        //注册
        long userId = userService.register(telephone, password);
        //发放体验金
        promotionService.issueNewUserExperienceCash(userId);
        return userId;
    }
}

注册里面做了2个事情一个是注册一个是发放体验金违反单一职责原则,如果不大量更改以下代码可以接收.

如果需要大量更改,比如后续注册成功增加发送短信提醒,我们再register方法增加一行发送短信违反了开闭原则,我们可以通过观察者模式来实现

重构后

//被观察者抽象接口
public interface RegObserver {
    void handleRegSuccess(long userId);
}

//发送体验金
public class RegPromotionObserver implements RegObserver {
    private PromotionService promotionService; // 依赖注入

    @Override
    public void handleRegSuccess(long userId) {
        promotionService.issueNewUserExperienceCash(userId);
    }
}

//发送短信
public class RegNotificationObserver implements RegObserver {
    private NotificationService notificationService;

    @Override
    public void handleRegSuccess(long userId) {
        notificationService.sendInboxMessage(userId, "Welcome...");
    }
}

public class UserController {
    private UserService userService; // 依赖注入
    //被观察者
    private List<RegObserver> regObservers = new ArrayList<>();

    // 一次性设置好,之后也不可能动态的修改
    public void setRegObservers(List<RegObserver> observers) {
        regObservers.addAll(observers);
    }

    public Long register(String telephone, String password) {
        //省略输入参数的校验代码
        //省略userService.register()异常的try-catch代码
        long userId = userService.register(telephone, password);
        //注册成功 通知被观察者
        for (RegObserver observer : regObservers) {
            observer.handleRegSuccess(userId);
        }

        return userId;
    }
}

异步非阻塞模式

可以查看Guava EventBus使用

 

与生产者、消费者、事件总线的区别

生产者消费者模式、观察者模式和事件总线是三种不同的设计模式或通信机制,它们有以下区别:

1. 目的和应用场景:
   - 生产者消费者模式主要用于解决多线程环境下的生产者和消费者之间的协作问题,确保数据的正确传递和处理。
   - 观察者模式主要用于实现对象之间的松耦合,当一个对象的状态发生变化时,它的所有依赖对象都能够自动收到通知并进行相应的更新。
   - 事件总线是一种用于解耦和组织组件之间通信的机制,通过事件的发布和订阅,实现组件之间的松耦合的消息传递。

2. 参与角色:
   - 生产者消费者模式中有生产者和消费者两个角色,生产者负责生成数据并放入缓冲区,消费者负责从缓冲区中取出数据并进行消费。
   - 观察者模式中有被观察者和观察者两个角色,被观察者负责维护观察者列表并通知观察者,观察者负责接收并处理被观察者的通知。
   - 事件总线中有事件发布者和事件订阅者两个角色,事件发布者负责发送事件,事件订阅者负责订阅感兴趣的事件并进行相应的处理。

3. 数据传递方式:
   - 生产者消费者模式中,生产者通过将数据放入共享的缓冲区,消费者从缓冲区中取出数据进行消费。
   - 观察者模式中,被观察者通过通知观察者的方式传递数据,观察者通过更新方法接收并处理被观察者传递的数据。
   - 事件总线中,事件发布者通过事件总线发送事件,事件订阅者通过订阅事件的方式接收事件。

4. 扩展性:
   - 生产者消费者模式主要用于多线程环境下的协作问题,适用于解决特定的场景。
   - 观察者模式可以适用于各种场景,可以方便地增加新的被观察者和观察者。
   - 事件总线是一种更通用的机制,在分布式系统、插件化系统等场景下都可以使用,并且可以方便地扩展和增加新的事件发布者和事件订阅者。

总之,生产者消费者模式、观察者模式和事件总线是三种不同的设计模式或通信机制,它们各自有自己的应用场景和特点,在不同的情况下选择适合的机制来解决问题。

 总结

生产者消费者模式:
生产者消费者模式是一种并发模式,用于解决生产者和消费者之间的同步问题。在这种模式中,有一个生产者和一个消费者,它们交替地生产或消费对象。生产者生产对象并将其放入队列中,消费者从队列中取出对象并进行处理。

观察者模式:
观察者模式是一种通知模式,用于解决对象之间的依赖关系。在这种模式中,有一个被观察者和一个观察者,它们相互依赖并通知对方状态的变化。被观察者发生变化时,观察者会收到通知并更新自身的状态。

事件总线模式:
事件总线模式是一种发布订阅模式,用于解决对象之间的通信问题。在这种模式中,所有对象都订阅事件总线中的消息,事件总线发布事件并将其传递给所有订阅者。对象之间可以通过事件总线进行通信,而无需了解彼此的实现细节。

 

posted @ 2020-04-10 10:25  意犹未尽  阅读(211)  评论(0编辑  收藏  举报