观察者模式

观察者模式的定义:多个对象间存在一对多依赖关系,当其中一个对象状态发生变化时,所有依赖于它的对象都要失去告诉并作出相应解决。

其中被依赖的对象为指标对象,或事件源,其余对象称为观察者,指标对象的状态变动称为事件。

观察者模式的实用场景

具体的观察者对象不明确,或者在编码阶段不明确。

实现形式

形象主题(subject)或者形象指标类,提供减少、移除观察者对象的办法,以及告诉所有观察者的办法。

具体主题(concrete subject)或者指标实现类,实现形象指标的所有形象办法。

观察者(Observer)接口,提供一个接管告诉的办法,当接管到主题的告诉办法后被调用。

具体观察者(Concrete Observer),观察者接口的实现类。

咱们能够在代码中依据以上构造疾速实现一个观察者模式的简略利用,JDK也提供了观察者模式的实现,然而明天咱们次要探讨Spring Framework的实现形式,所以,对前者不做探讨。

Spring Framework对观察者模式的实现

为不便程序员调用,Spring提供了现成的观察者模式,所以程序员不再须要本人写代码实现观察者模式,在Spring中只须要简略几步即可实现。

Spring提供了以下几个组件:

  1. ApplicationEvent:事件抽象类,通过扩大此类实现用户事件。
  2. ApplicationEventPublisherAware:事件公布器接口,用户的指标类通过实现该接口、通过Spring框架实现事件公布。
  3. ApplicationListener 观察者(监听器)接口,用户通过该接口实现对事件公布器公布的ApplicationEvent事件的监听,该接口只有一个办法:void onApplicationEvent(E event),该办法有Spring容器在接管到事件公布器公布的对应事件后调用。
  4. @EventListener:通过注解形式实现的观察者(监听器),作用及成果同ApplicationListener接口

具体实现

最简略无效的解释莫过于举例,上面举例说明Spring事件机制的具体实现形式。

咱们先假如一个场景:用户类userService有一个用户注册的办法userRegister,注册胜利后咱们须要通过短信、微信等不同的形式给相干方发告诉。

  1. 依照Spring事件机制的实现形式,咱们首先须要定义用户注册事件:
public class userRegisterEvent extends ApplicationEvent {    private userService userService;    /**     * Create a new {@code ApplicationEvent}.     *     * @param source the object on which the event initially occurred or with     *               which the event is associated (never {@code null})     */    // 通过实现ApplicationEvent接口,创立一个事件    public userRegisterEvent(Object source) {        super(source);        this.userService = (userService) source;    }}
  1. userService类是用户服务类,依照上述约定,userService类提供一个用户注册的办法。因为咱们须要在用户注册胜利后公布告诉,所以,userService须要具备事件公布的能力,须要实现ApplicationEventPublisherAware接口:
@Component@Slf4jpublic class userService implements ApplicationEventPublisherAware {    //定义事件公布器    ApplicationEventPublisher publisher;    public String name;    //默认是单例bean,在容器初始化的时候就会被创立、初始化    public userService(){        System.out.println("userService constructed。。。");    }    //自定义的事件公布办法,与利用进行绑定,在利用某一特定事件实现后,通过容器的事件公布器将事件公布到容器中    public void userRegister(String userName){      log.info("User register sucessful") ;      this.setName(userName);      publisher.publishEvent(new userRegisterEvent(this));    }    //实现事件公布器的办法,获取到容器中的事件公布器    @Override    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {        this.publisher=applicationEventPublisher;    }    public String getName(){        return this.name;    }    public void setName(String name){        this.name=name;    }}
  1. 剩下的就是要实现观察者了,由以上的介绍咱们晓得Spring有两种形式实现观察者,首先通过ApplicationListener的形式实现观察者。为了简化逻辑,监听到用户事件之后咱们只是简略打印一下即可:
@Component@Slf4jpublic class UserReigisterListener implements ApplicationListener<userRegisterEvent> {    //通过实现接口ApplicationListener,监听容器中公布的特定事件    @Override    public void onApplicationEvent(userRegisterEvent event) {        userService  user = (userService)event.getSource();        if (user != null){            log.info("I have a message from userService:" + user.getName());        }    }}
  1. 通过注解形式实现监听者:
@Component@Slf4jpublic class SmsSendListener {    @EventListener    @Order(0)    public void onRegister(userRegisterEvent event){        userService  user = (userService)event.getSource();        if (user != null){            log.info("I will send SMS to :" + user.getName());        }    }}

实现了,能够测试了。

编写启动类,测试:

@Slf4jpublic class App {    public static void main( String[] args )    {        ApplicationContext ctx=new AnnotationConfigApplicationContext(commonConfig.class);                //获取userService实例        userService us=ctx.getBean("userService",userService.class);        us.userRegister("Zhang san");    }}

运行:

22:50:33.538 [main] INFO org.example.service.SmsSendListener - I will send SMS to :Zhang san22:50:33.538 [main] INFO org.example.service.UserReigisterListener - I have a message from userService:Zhang san

从打印后果能够看到,userService类的办法userRegister通过调用Spring框架的事件公布器,将用户 Zhang san的注册胜利的信息告诉给了两个监听器(观察者)。

这样咱们就采纳非常简单的形式、通过Spring框架实现了观察者模式,将用户注册胜利的消息传递给了观察者,不同的观察者能够依据业务要求做出不同的响应。

而且,不论是通过实现接口、还是采纳注解,咱们都能够十分不便的注册多个观察者,比方咱们能够疾速实现一个微信告诉的观察者、邮件告诉的观察者等等。

要害是,减少观察者不须要和事件源(指标类,比方上述案例的用户服务类)产生任何耦合,不须要对指标类做出任何改变。

Spring框架事件机制的原理后续剖析。