当前位置: 首页 > 后端技术 > Java

观察者模式_0

时间:2023-04-01 22:53:56 Java

设计模式的观察者模式是一个极其重要的设计模式,也是我这几年在开发过程中使用最多的设计模式。本文首先总结了观察者模式的基本概念和demo实现,接着介绍了观察者模式在Java和Spring中的应用,最后总结了观察者模式的应用场景和优缺点。1.概念理解观察者模式:定义对象之间一对多的依赖关系,这样每当一个对象的状态发生变化时,它相关的依赖对象就可以得到通知并自动更新。主要用于多个不同的对象对一个对象的某个方法做出不同的反应!这个概念是什么意思?也就是说,如果在A的业务逻辑中使用观察者模式调用B的业务逻辑,即使B的业务逻辑报错,仍然不影响A的执行。例如,在我公司最近开发城市系统的过程中,提交订单成功后,需要删除购物车中的信息。如果我先写订单提交逻辑,再写购物车的删除逻辑,是没有问题的,但是程序的健壮性很糟糕。业务应该分为两步,一是处理订单成功处理逻辑,二是删除购物车中的信息。即使删除购物车报错,也不影响提交订单的逻辑。那么应该怎样做才不会互相影响呢?购物车对象中需要有一个删除购物车的方法,还有一个对象A注入(添加)购物车对象并通知(notify)购物车执行它的方法。执行时,先调用对象A的add方法,将购物车对象添加到对象A中。订单提交成功后,调用对象A的notify购物车方法,执行清空购物车的逻辑。在观察者模式中,购物车称为观察者,对象A称为目标对象。在面向接口编程的原则下,观察者模式应该包括四个角色:1.目标接口(subject):它是一个抽象类,是所有目标对象的父类。它用一个列表记录当前目标对象有哪些观察者对象,并提供添加、删除观察者对象、通知观察者对象的方法声明。2、具体目标类:可以有多个不同的具体目标类,它们同时继承Subject类。目标对象是具体目标类的对象,具体目标类负责定义自己的事务逻辑,并在状态发生变化时通知其所有观察者对象。3、观察者接口(Listener)也是一个抽象类,是所有观察者对象的父类;它为所有观察者对象定义了一个名为update(notify)的方法。当目标对象的状态发生变化时,它会通过调用update(notify)方法通知所有观察者对象。4、具体的观察者类,可以有多个不同的具体观察者类,它们同时继承Listener类。观察者对象是具体观察者类的对象。每个具体的观察者类都必须重新定义Listener类中定义的update(notify)方法,并在这个方法中实现自己的任务逻辑,当它被通知时(目标对象调用它的update(notify)方法)就执行自己特有的任务.在我们的例子中,它是一个购物车观察者,当然也可以有其他的,比如日志观察者。我们基于四个角色来实现这个demo。2、案例实现目标接口:包括注册、移除、通知监听器的方法声明。/***Thisistheobservedobject*Targetclass*@authortcy*@Date17-09-2022*/publicinterfaceSubjectAbstract{//注册监听器publicvoidregisterListener(Tt);//移动移除监听器publicvoidremoveListener(Tt);//通知监听器publicvoidnotifyListener();}目标接口实现:需要一个listenerList数组存放所有的观察者,需要定义add和remove观察者的方法。notify方法通知所有观察者对象。/****具体目标类*@authortcy*@Date17-09-2022*/publicclassSubjectImplimplementsSubjectAbstract{//监听器注册列表privateListlistenerList=newArrayList<>();@OverridepublicvoidregisterListener(ListenerAbstractmyListener){listenerList.add(myListener);}@OverridepublicvoidremoveListener(ListenerAbstractmyListener){listenerList.remove(myListener);}@OverridepublicvoidnotifyListenermy(){for(ListenerAbstract:listenerList){System.out.println("收到推送事件,开始调用异步逻辑...");我的监听器.onEvent();}}}观察者接口:声明响应方法/****Observer-Interface*@authortcy*@Date17-09-2022*/publicinterfaceListenerAbstract{voidonEvent();}观察者接口:实现响应方法和句柄清除购物车的逻辑。/***具体观察者类购物车*@authortcy*@Date17-09-2022*/publicclassListenerMyShopCartimplementsListenerAbstract{@OverridepublicvoidonEvent(){//...省略购物车处理逻辑System.out.println("删除购物车中的信息...");}}我们使用Client来模拟提交订单的操作。/***先使用具体目标对象的registerListener方法添加具体的观察者对象,*然后调用其notify方法通知观察者*@authortcy*@Date17-09-2022*/publicclassClient{publicstaticvoidmain(String[]args){System.out.println("订单成功处理逻辑...");//创建目标对象SubjectImplsubject=newSubjectImpl();//将具体的观察者注册到目标对象ListenerMyShopCartshopCart=newListenerMyShopCart();//向观察者注册监听器subject.registerListener(shopCart);//发布事件通知观察者subject.notifyListener();}}这样就实现了订单处理逻辑和购物车逻辑的解耦,即使购物车逻辑报错,也不会影响订单处理逻辑。由于观察者模式是一种很常见的模式,抽象观察者和抽象目标类的方法声明是固定的,作为Java的一种高级语言,Java的设计者只是简单的构建了两个接口,开发者通过实现接口就可以直接使用观察者模式.3、Java中的观察者模式在Java中,观察者模式是通过java.util.Observable类和java.util.Observer接口来定义的。只要实现了它们的子类,就可以编写观察者模式的实例。Observable类是一个抽象目标类。它有一个Vector向量,用来保存所有需要通知的观察者对象。下面介绍一下它最重要的三个方法。voidaddObserver(Observero)方法:用于向向量中添加一个新的观察者对象。voidnotifyObservers(Objectarg)方法:调用vector中所有观察者对象的update()方法,通知它们数据变化。通常较晚加入向量的观察者会较早收到通知。voidsetChange()方法:用于设置一个boolean类型的内部标志位,表示目标对象发生了变化。notifyObservers()只会在为真时通知观察者。Observer接口是一个抽象的观察者,它监视目标对象的变化。当目标对象发生变化时,通知观察者并调用voidupdate(Observableo,Objectarg)方法进行相应的工作。我们基于两个Java接口转换案例。具体目标类:/***具体目标类*@authortcy*@Date19-09-2022*/publicclassSubjectObservableextendsObservable{publicvoidnotifyListener(){super.setChanged();System.out.println("收到推送消息...");super.notifyObservers();//通知购物车事件的观察者}}具体观察者类:/***观察者实现类*@authortcy*@Date19-09-2022*/publicclassShopCartObserverimplementsObserver{@Overridepublicvoidupdate(Observableo,Objectarg){System.out.println("清空购物车...");}}仍然是模拟订单处理逻辑的客户端。/***@authortcy*@Date19-09-2022*/publicclassClient{publicstaticvoidmain(String[]args){System.out.println("订单提交成功...");SubjectObservableobservable=newSubjectObservable();观察者shopCartObserver=newShopCartObserver();//购物车observable.addObserver(shopCartObserver);observable.notifyListener();}}这样也可以实现观察者逻辑,但是Java中的观察者模式有一定的局限性。Observable是类,不是接口,没有实现Serializable,所以不能序列化和它的子类,也不是线程安全的,不能保证观察者的执行顺序。JDK9之后已经启用。写Java的恐怕没有一个不用Spring的。作为一个优秀的开源框架,Spring也有观察者模式的大量应用,而Spring是在java的基础上进行改造的,避免了Java观察者模式的缺点。地方。4.Spring如何使用观察者模式在第一章中,典型的观察者模式包含四种角色:目标类、目标类实现、观察者、观察者实现类。Spring下的观察者模式略有不同,Spring对其进行了部分修改。Event:Spring中定义了顶级事件ApplicationEvent,该接口最终继承了EventObject接口。只是在基础上增加了构造和获取当前时间戳的方法。所有的Spring事件都必须实现这个接口,比如Spring内置的ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent……看名字就大概知道这些事件用在什么地方,容器刷新后,什么时候启动,什么时候它停止...目标类接口:Spirng中的ApplicationEventMulticaster接口是实例中的目标类。我们可以将我们的目标接口与ApplicationEventMulticaster接口进行比较,它们非常相似。Observer接口:ObserverApplicationListener用于监听事件,只有一个方法,在onApplicationEvent事件发生后执行。与我们示例中的抽象观察者没有太大区别。目标类实现:在我们的例子中,目标类的职责直接在一个类中实现,注册监听器,广播事件(调用监听器方法)。在Spring中,这两个实现类是分开的。registerListeners()方法会在Spring启动过程中被调用。看名字我们大概已经知道是注册所有的监听器了。该方法完成了原目标类的注册监听职责。在Spring中,使用事件源ApplicationContext来广播事件,用户不需要显示调用监听器的方法,而是交给Spring来调用,而这个方法完成了原目标类的广播事件职责.我们继续基于Spring的观察者模式改造我们的案例。购物车事件:/***购物车事件*@authortcy*@Date19-09-2022*/@ComponentpublicclassEventShopCartextendsApplicationEvent{privateStringorderId;publicEventShopCart(Objectsource,StringorderId){super(source);this.orderId=orderId;}publicEventShopCart(){super(1);}}Publisher(模拟Spring调用监听器的方法,实际开发不需要写):/***Publisher*@authortcy*@Date19-09-2022*/@ComponentpublicclassMyPublisherimplementsApplicationContextAware{private应用上下文应用上下文;@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{this.applicationContext=applicationContext;任何人都可以得到消息**@parammyEvent*/publicvoidworkEvent(EventShopCartmyEvent){//这个方法会调用监听器实现的方法applicationContext.publishEvent(myEvent);}}监听器:/***Listener*@authortcy*@Date19-09-2022*/@ComponentpublicclassListenerShopCartimplementsApplicationListener{@OverridepublicvoidonApplicationEvent(EventShopCartmyEvent){System.out.println("清除购物车成功...");}}客户端模拟调用:/***@authortcy*@Date19-09-2022*/publicclassClient{publicstaticvoidmain(String[]args){ApplicationContextac=newAnnotationConfigApplicationContext("cn.sky1998.behavior.observer.spring");System.out.println("订单提交成功...");MyPublisherbean=ac.getBean(MyPublisher.class);EventShopCartmyEvent=ac.getBean(EventShopCart.class);bean.workEvent(我的事件);}}通过Spring实现观察者模式比我们手动编写简单的使用Spring实现观察者模式时,我们不需要管理观察者接口、目标接口和目标实现。我们只负责继承ApplicationEvent类来定义自己的事件,并实现ApplicationListener接口来实现我们的Observer,在对应的业务中调用applicationContext.publishEvent(newShopCartEvent(cmOrderItemList)),实现了observer模式。读者可以拉取完整代码在本地学习,全部测试完成后上传到码云。五、总结Spring采用观察者模式。写作变得更加透明。虽然观察者模式的概念是:一对多依赖,但并不一定意味着有多个观察者。我们的例子都使用一个观察者。它很好的降低了target和observer之间的耦合关系,target和observer之间建立了触发机制,这也让它成为最常见的设计模式。设计模式的研究应该是系统的。我推荐你阅读我过去发表的设计模式文章。1.设计模式概述2.设计模式的工厂方法和抽象工厂3.设计模式的单例和原型4.设计模式的建造者模式5.设计模式的代理模式6.设计模式的适配器模式7.设计模式的桥梁设计模式模式八、组合模式九、设计模式装饰器模式十、设计模式外观模式十一、外观模式享元模式十二、设计模式责任链模式十三、设计模式命令模式十四、设计解释器模式设计模式十五、设计模式迭代器模式十六、设计模式中介模式十七、设计模式备忘录模式