星空网 > 软件开发 > ASP.net

观察者模式分析

概念

组件关系

观察者模式分析

上图描述了模式中涉及到的两个重要角色及其相互之间的依赖关系。

在后文中我们将称Observable为“目标”,称“Observer”为观察者,简称“观察者模式”为“模式”。目标持有一个观察者集合,成之为“清单”。

JDK的支持

在java.util包中,有两个class提供了对模式的支持:

观察者模式分析

对其API介绍如下:

Observable

addObserver (o: Observer): void

添加观察者:如果新的观察者和清单中已有的观察者不同,就把新的观察者添加到清单中。

deleteObserver (o: Observer): void

删除观察者:如果观察者在清单中,就把观察者从中移除。

deleteObservers (): void

清空观察者:清空清单中的观察者。

countObservers (): int

统计观察者:统计清单中的观察者个数。

setChanged (): void

设置变更标识:只有设置了变更标识,目标才会通知观察者。

hasChanged (): boolean

获取变更标识:一般用于通知之前获取,进行判断是否有必要进行通知。

clearChanged (): void

清除变更标识:一般用于在通知了观察者之后进行清除,以便下一次的设置、检查和通知。

notifyObservers (): void

通知观察者:如果观察目标发生了变化(通过调用hasChanged方法获取),就通知清单中的观察者,并调用clearChanged方法来清除变化标识。这个方法需要在调用setChanged方法之后调用。

notifyObservers (arg: Object): void

通知观察者:如果观察目标发生了变化(通过调用hasChanged方法获取),就通知所有的观察者,并调用clearChanged方法来清除变化标识。这个方法需要在调用setChanged方法之后调用。
与前一个通知方法相比,这个方法可以在通知观察者时提供额外的数据。

Observer

update (o: Observable, arg: Object): void

更新:目标通知观察者,实质上就是调用观察者的此方法。第一个参数是通知的目标,第二个参数是目标额外提供的数据。

如果目标使用notifyObservers ()而不是notifyObservers (arg: Object)通知,观察者所获取到的额外数据仅仅是null。

三个阶段

模式分为三个明显的阶段:注册、通知(监控)、注销。

观察者模式分析

改进

我们基于以下的问题思考改进的方案:

1. 每一次通知都需要设置变更标识

直接调用notifyObservers是不能真正实施通知的,必须先调用setChanged,再调用notifyObservers才能把通知进行下去。

2. 同一个观察者类,不同的实例被视为不同的观察者

这就导致同一个观察者类的多个实例,可以在目标的清单中并存。按需要判断这是应用应该维护的还是应该避免的,如果要避免,需要改进。

3. 谁负责注册,什么时候注册

目标负责注册观察者,还是观察者主动请求注册到目标的清单?

由观察者负责注册比较好,这样新增或者删除一个观察者,只需要修改观察者本身,而不需要修改目标。在模式中,目标是核心,维持核心的稳定,可以降低整个体系的动荡。

在spring环境可以支持将目标实例自动注入观察者实例,观察者在初始化完成之后,调用目标的注册方法,将自身注册到清单即可,这样目标只需要专注于清单,而不是具体的观察者。如果脱离spring环境,需要考虑类似的方案。

javax.annotation.PostConstruct注解用于方法,可以使这个方法在构造器完成之后被调用,注册工作可以写到这样的方法里。

PS:观察者的监控生命线一般和系统的一次运行的生命线一致,在这里我们不关心观察者的注销。

改进的API

在上述问题的思考下,我们提供了cn.sinobest.jzpt.template包,其中的两个抽象类分别用于改进目标和观察者:

观察者模式分析

ObservableTemplate

package cn.sinobest.jzpt.template;import java.util.Observable;/** * 观察目标类模板.<br> * 用于实现业务扩展. * @author lijinlong * */public abstract class ObservableTemplate extends Observable {  @Override  public void notifyObservers(Object data) {    setChanged();    super.notifyObservers(data);  }}

ObserverTemplate

package cn.sinobest.jzpt.template;import java.util.Observer;import javax.annotation.PostConstruct;/** * 观察者模板类,用于实现业务扩展.<br> * @author lijinlong * */public abstract class ObserverTemplate implements Observer {  /**   * 这种实现是保证同一个类的实例的hashcode相同,在封装到集合中的时候,可以保证不会有多个实例.<br>   */  @Override  public int hashCode() {    return this.getClass().getName().hashCode();  }    /**   * 根据hashCode来判断是否equal.<br>   */  @Override  public boolean equals(Object obj) {    if (obj == null)      return false;    return obj.hashCode() == this.hashCode();  }    /**   * 将Observer实例注册到特定的Observable实例.<br>   */  @PostConstruct  public abstract void register();}

业务示例API

基于改进的template,这里提供两个示例API:

Observable

package cn.sinobest.jzpt.business;import org.springframework.stereotype.Component;import cn.sinobest.jzpt.template.ObservableTemplate;@Component("business.observable.demo")public class BusinessObservableDemo extends ObservableTemplate {  public void business() {    // do business    notifyObservers();  }}

根据需要,Observable如果不负责业务处理,那么可以不定义任何方法。

Observer

package cn.sinobest.jzpt.business;import java.util.Observable;import javax.annotation.PostConstruct;import javax.annotation.Resource;import org.springframework.stereotype.Component;import cn.sinobest.jzpt.fzywgz.observe.ObserverTemplate;@Component("business.observer.demo")public class BusinessObserverDemo extends ObserverTemplate {  @Resource(name="business.observable.demo")  private Observable observable;    @Override  public void update(Observable o, Object data) {    // do something  }  @Override  @PostConstruct  public void register() {    observable.addObserver(this);  }}

在上述的示例中,有两处空白:

1. BusinessObservableDemo的business谁来调用?

可以是一个service组件,或者Controller组件。

2. BusinessObserverDemo的update做了什么?

update里面可以调用一个service组件提供的业务接口。

应用模式思考

web环境中,我们常见到的角色有控制器、服务组件、子服务组件、一般组件、数据库访问组件、视图解析组件:

1. 控制器

JavaEE中的Servlet、Spring MVC中的Controller都可以担当这个角色,对上接收前台请求,解析数据,封装结果,返回视图;对下负责调用服务组件,完成业务。

2. 服务组件和子服务组件

使用控制器的传递的参数,完成业务,返回结果给控制器。服务组件一般是分层的,在一次请求中,负责完成完整业务的服务组件,可以称为“主服务组件”;而这个服务组件又是通过调用其它服务组件的提供的接口来完成业务的,那么这些被调用的服务组件在当前的请求处理中,就担当着“子服务组件”的角色。一个服务组件,在不同的请求中,可能分别担当着“主服务组件”和“子服务组件”的角色。

3. 一般组件

一般组件没有鲜明的角色,用于支持其它组件的工作。或者说无法归为控制器组件、服务组件、数据库访问组件等鲜明组件的组件,称之为一般组件。如spring中提供了Controller注解控制器组件,提供了Service注解服务组件,提供了Repository注解数据库访问组件,也提供了Component来注解一般的组件。

4. 其它

略。

服务+服务模式

在引入了观察者模式之后,我们多了两个角色:目标和观察者。这两个角色在web环境中应该有其新的身份,假如我们把目标和观察者都定义为服务组件,可以得到一次请求中的时序图如下:

观察者模式分析

这个模式具有一些特点,决定了它适用的场景和不适用的场景:

1.

Technorati 标签: 设计模式,观察者模式



原标题:观察者模式分析

关键词:

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

【掘金Shopee蓝海】教你如何使用知虾找到蓝海? :https://www.goluckyvip.com/news/7195.html
上海港进口液位计报关申报手续,清关代理流程知识科普:https://www.goluckyvip.com/news/7196.html
如何测评养号海外版抖音TikTok? :https://www.goluckyvip.com/news/7197.html
上海进口压力变送器报关操作流程,代理清关申报手续解析:https://www.goluckyvip.com/news/7198.html
亚马逊、Lazada、Shopee、速卖通自养号测评可以使用全自动下单吗? :https://www.goluckyvip.com/news/7199.html
DHL三月动作不断,欲称霸国际物流?:https://www.goluckyvip.com/news/72.html
亚马逊掀起算法革命:A9已死 COSMO当立? :https://www.kjdsnews.com/a/1836493.html
2月新茶饮开店腰斩 加盟门槛一降再降 :https://www.kjdsnews.com/a/1836494.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流