当前位置: 首页 > 科技观察

阿里P6+专访:引入观察者模式?

时间:2023-03-19 14:31:38 科技观察

消息队列(MQ),一种可以实现生产者到消费者单向通信的通信模型,也是现在常用的主流中间件。常见的有RabbitMQ、ActiveMQ、Kafka等,它们也有很多优点,比如解耦、异步、广播、削峰等。在设计模式中,还有一种模式可以有效的实现解耦和异步的特性,那就是观察者模式,也称为发布-订阅模式。今天阿兵就给大家分享一下这种在实际开发中比较常见的模式的轮廓。什么是观察者模式?它的目的是什么?当一个对象的状态发生变化时,其他注册的对象可以观察到这一变化,从而做出自己相应的变化。这样就达到了降低依赖和解耦的效果。举个例子,就像微信朋友圈,以当前个人为订阅者,以好友为主题。当一个人发布动态朋友圈时,他的朋友就可以看到这个朋友圈,并且可以自主选择点赞或者评论。感觉有点抽象,我们来看看它的主要作用:Subject:主要由一个类实现的可观察接口,通知观察者使用attach方法,detach方法取消观察。ConcreteSubject(具体主题):是实现主题接口的类,处理观察者中的变化Observe(观察者):观察者是一个以对象为界的接口,根据主题的变化进行更新。这种方式作用不多,但感觉还是有点抽象。让我们看一下具体的示例代码。我们以上面的朋友圈为例来看代码实现topic定义先定义增删关系并通知订阅者}@Overridepublicvoiddetach(Observerobserver){//解除订阅关系observers.remove(observer);}@OverridepublicvoidnotifyObservers(Stringmessage){//通知订阅者for(Observerobserver:observers){observer.update(message);}}}然后创建一个具体topic,构建容器维护订阅关系,支持增删关系,并通知订阅者publicinterfaceObserver{//处理业务逻辑voidupdate(Stringmessage);}创建观察者接口,方便我们管理publicclassFriendOneObserverimplementsObserver{@Overridepublicvoidupdate(Stringmessage){//模拟业务逻辑System.out.println("FriendOne知道thatyouhavepostedsomething"+message);}}最后创建具体的观察者类,实现观察者接口的update方法,处理自己的业务逻辑publicclasstest{publicstaticvoidmain(String[]args){ConcreteSubjectsubject=newConcreteSubject();//这里假设添加了一个好友朋友圈动态主题.notifyObservers("第一条朋友圈消息");//输出结果:FriendOne知道你发了第一条朋友圈//FriendTwo知道你发了第一条朋友圈//这里是发现twoObserver推荐卖茶,删除好友看看测试结果。通过ConcreteSubject维护订阅关系。通过notifyObservers方法通知订阅者后,观察者获取消息并处理自己的业务逻辑。这里细心的小伙伴已经达到了理解耦合的效果,同时减少了依赖,每个观察者不需要知道发布者处理什么业务逻辑,也不需要依赖发布者的任何业务模型,并且只关心它需要处理的逻辑。如果新增业务,我们只需要创建一个新的订阅者,维护在观察者容器中即可,这也符合我们的开闭原则。这只是一个同步实现,我们还可以扩展其他异步实现,或者使用多线程等实现。观察者模式在框架中的应用应该很多。第一个熟悉JDK的人应该知道java.util包中除了常用的collections和maps之外还有一个Observable类。它的实现方式其实就是观察模式。还有增删改查的方??法。这里需要注意的是,他使用的是Vector作为订阅关系的容器。同时,他在自己的定义方法中加入synchronized关键字修饰类,实现线程安全。这里贴出关键源码。有兴趣的同学可以自己打开看各个方法的评论。第二种在Spring中有一个ApplicationListener,也是用观察者模式处理的。以ApplicationEventMulticaster为主题,里面有增删改查,通知等。Spring有一些内置事件。当某个操作完成时,会发出某些事件动作。其处理方式也是上述方式。当然,里面还有很多。我没有详细说明。有兴趣的同学可以仔细了解一下Spring的启动过程。importjava.util.EventListener;/***应用事件监听器要实现的接口。*基于观察者设计模式的标准{@codejava.util.EventListener}接口*。观察者模式**importjava.util.EventListener;/***Interfacetobeimplementedbyapplicationeventlisteners.*Basedonthestandard{@codejava.util.EventListener}interface*fortheObserverdesignpattern.//这里也说明了采用观察者模式**

AsofSpring3.0,anApplicationListenercangenericallydeclaretheeventtype*thatitisinterestedin.WhenregisteredwithaSpringApplicationContext,events*willbefilteredaccordingly,withthelistenergettinginvokedformatchingevent*objectsonly.**@authorRodJohnson*@authorJuergenHoeller*@paramthespecificApplicationEventsubclasstolistento*@seeorg.springframework.context.event.ApplicationEventMulticaster//主题*/@FunctionalInterfacepublicinterfaceApplicationListenerextendsEventListener{/***Handleanapplicationevent.*@parameventtheeventtorespondto*/voidonApplicationEvent(Eevent);}第三种GoogleGuava的事件处理机制GuavaEventBus在设计模式上也采用了观察者设计模式EventBus。目前有两种实现方式:EventBus//同步阻塞方式AsyncEventBus//异步非阻塞方式EventBus也提供了一系列方法方便我们使用:register方法作为添加观察者使用起来非常方便。unregister方法删除观察者。post方法发送通知消息等。您可以通过添加@Subscribe注解来创建订阅者。详情请参考官网。真实业务改造的例子框架应用的例子实在是太多了,在业务场景中其实可以用到的地方也很多。这里我给大家举个例子。新用户注册成功后,我们需要对用户做两件事。第一个是发送注册成功消息,第二个是向新用户发送优惠券。看到这个问题,你可能首先想到使用MQ消息处理。是的,确实可以使用消息,但是这里我们使用观察者模式来实现这个问题。同时我们可以给你演示是同步的还是异步的。publicclassSendNewPersonCouponObserverimplementsObserver{ExecutorServicepool=Executors.newFixedThreadPool(2);@Overridepublicvoidupdate(Stringmessage){Futurefuture=pool.submit(newCallable(){@OverridepublicStringcall()throwsException{TimeUnit.SECONDS.sleep(3);//处理响应返回“调用优惠券服务并返回结果”的业务逻辑;}});try{//假设等待200毫秒没有得到返回值,则认为失败System.out.println(future.get(4000,TimeUnit.MILLISECONDS));}catch(Exceptione){//执行异步获取失败//记录日志,定时任务重试等}//第一种不关心返回值结果Threadthread=newThread(newRunnable(){@SneakyThrows@Overridepublicvoidrun(){//模拟服务调用线程休眠3秒TimeUnit.SECONDS.sleep(3);System.out.println("发送新优惠券");}});thread.start();System.out.println("执行异步返回");}}publicclassSendSuccessMessageObserverimplementsObserver{@Overridepublicvoidupdate(Stringmessage){//处理业务逻辑System.out.println("注册成功");}publicstaticvoidmain(String[]args){//假设用户注册成功,直接通知观察者,并改变做自己的事情。ConcreteSubjectsubject=buildSubject();subject.notifyObservers("");}privatestaticConcreteSubjectbuildSubject(){ConcreteSubjectsubject=newConcreteSubject();subject.attach(newSendSuccessMessageObserver());subject.attach(newSendNewPersonCouponObserver());returnsubject;}}这里新写了两个观察者,主要是看首先这里的SendNewPersonCouponObserver异步开启一个新的线程来处理我们的业务逻辑,当我们关心返回值时,我们可以使用Future获取返回结果,当我们不关心返回值时,我们可以直接开启普通线程.这个例子其实整体比较简单,主要是阐明异步线程处理,当然也可以用GuavaEventBus来实现,而且也不复杂,有兴趣的朋友可以自己试试,目前有更好的中间件MQ消息队列就是用来处理这个业务问题的,让我们可以更从容的面对这样的场景,但是有些资源不够用,不想引入新的系统秒。我们仍然可以使用这种方法来处理问题。设计模式不是代码,而是学习每一种模式的思想,分别处理什么样的业务场景。综上所述,看完这篇文章,不知道大家有没有发现。其实整个内容都是围绕着解耦的思想来写的。观察者模式作为一种行为类型的设计模式,主要是针对不同业务行为的代码解耦。合理使用设计模式可以让代码结构更加清晰,同时满足不同小模块满足单一职责的要求,以及开闭原则,从而实现前面写工厂模式说的,提高了代码的可扩展性,以及维护成本低的特点。我是敖丙,知道的越多,不知道的越多,下期见。

猜你喜欢