`
herman_liu76
  • 浏览: 99431 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

通过监听与过滤器模式使用来体会java中对象关系

 
阅读更多
    作为面向对象的语句,java的三大基本特性:封装、继承、多态。但随着做的系统越来越复杂,发现组织对象之间的关系是更重要的技能。spring我认为IOC容器的好处之一就是方便的组织系统中的对象关系。
    感觉用java后,有了一个模仿现实世界,来组织软件系统的方式。越来越感觉软件设计如同生活场景设计有相似之处。想到一句话,人的本质是一切社会关系的总和。正好也体会到,组织好系统中对象的各种关系是非常重要的,甚至我认为一个系统中,关系是最主要的。了解了对象的关系,系统就明白了。

    先从简单的监听模式,来引入对象之间的关系。再介绍一下最近改造一个系统,所使用到的filterchain模式来,进一步介绍我是如何思考对象之间的关系的。

一、监听器模式
    为什么说监听?监听很好体现了关系这一点,很多书介绍模式都比较简单。

    这是非常常见的设计模式。比如Web开发,可以监听web容器启动,可以监听session事件等等。事件源注册监听器之后(可以是多个,放在自己的容器中),当事件源触发事件,每个监听器就可以得到消息对象进行自己的处理;更形象地说,监听者模式是基于:注册-回调的事件/消息通知处理模式,就是被监控者将消息通知给所有监控者。




如上图所示:
会议作为被监听者,一般是单例模式,想监听的就可以方便的找到它的实例。
会议内有一个容器,放着监听者(它们都实现相同的接口),接口由会议提供。
会议发生了事件,就循环容器,按接口调用一个个监听者的接口方法即可。

监听者都实现了公共的接口。

这个模式很简单,接下来扩展一下,有对象产生监听器,来稍微复杂一点的。

二、带有复杂的引用关系监听
    来一个复杂的场景吧,比如:局长安排秘书监听一个会议,会议结束了秘书直接通知处长办理(秘书不认识处长,局长给秘书一个电话号码),处长办理好了汇报给局长。

    1.会议是被监听的对象,类似于服务端,不依赖监听者。比如你自己的代码会监听spring容器的启动,比如监听TCP通讯的事件。被监听的对象,比如会议,通常提供这个接口,另外会提供一个容器,放置监听者。被监听的对象通常是一个单例,用静态的getInstance就可以找到。监听者可以方便的找到被监听的对象。监听者可以受人指使去监听,可以自己就想去听。




  • 1.new秘书设置给自己引用
  • 2.new处长设置给自己引用,由于把this传入,并让处长记住自己,内部再调用处长的设置局长的方法。
  • 3.派秘书参会,由于秘书并没有自己的引用,这样参加好,回调时,秘书无法汇报给局长。
  • 4.派秘书参会,把自己引用的处长设置进去,这样,秘书开好会,可以转达处长,处长由于前面设置了局长的引用,处长办好事可以汇报给局长了。


    2.局长new一个秘书,再new一个处长同时把自己this注入给处长,并调用处长的设置局长的方法。这样会相互持有,new秘书时没有注入this,只是单向引用。关系见上图右下角中圈中的表示。

    3.秘书对象必须实现一个会议的接口,同时局长一定有一个方法,把处长设置让秘书持有,这样秘书监听到事件通知处长。局长先知道有这个会,所以会调用会议的方法,把秘书放置到会议容器中去。

    4.一旦会议结束了,会议从自己的容器中取出秘书,并调用秘书实现的接口方法。秘书持有处长引用,在接口方法中调用处长的方法,处长肯定有一个汇报方法,向自己持有的局长对象汇报工作。

    特意没有让秘书持有局长的引用。这样场景类似于局长刚有了一个秘书,通知他去开个会,只告诉了处长的联系方式(设置处长给秘书),让他开好会后,把会议要求告诉处长。但局长没给秘书自己的手机号。假如生活中,秘书手机丢了,会开好发现找不到处长了,处长引用是空值,而且又没有持有局长的引用,这下监听接口就调用失败了。


三、filterchain中对象及引用关系设计

    过滤链模式正好最近在项目中使用。也因为Web应用中大家用filter很常见,所以我叫此模式为过滤链。另外在druid的源码中也看到过这个模式,druid是阿里面向监控的连接池工具。它包装了所有的数据库连接中的对象,内部引用代理对象,这样有了代理,就在原来所有的数据库对象操作中,都强行插入自己的过滤器,过滤后再执行真正引用的原始对象。

    另外,我设计系统中对象时,对象基本上分为两种:“配置对象”“业务对象”。当然,这是相对的,配置对象有时也可能是业务对象,特别是在后台管理系统中。“配置对象”之间的引用是设计的重点。

    用“铁打的营盘流水的兵”来比喻,铁打的营盘就是“配置对象”,没业务之前我先建一个营盘,内部有各机关,部门。兵就是“业务对象”,在营盘中不断接收、使用、送别士兵。与软件系统对应的是,营盘对象一盘都是singleton对象,营盘中的对象很多都是相互引用的,不过为了不太乱,还是要分类别,加容器中管理。如果职能部门的人员要组织在不同的部门一样。软件的设计与生活中的设计是多少有相似性啊。
    而兵都是一个个new出来的,是被营盘处理的对象,通常来自外部的请求。营盘对象一般一直存在于内存中(从配置表或者配置文件加载),速度快,而发生变化的情况少。兵是从外部产生的,在内存中处理好后,就消失(比如持久化到数据库)。生活中,学校里的机构与老师都是配置对象,学生是业务对象。医院里的机构与医生是配置对象,病人是业务对象。

    回到过滤链模式中,先用生活中这样的模式举例。比如体检,给每一个受检人员的单据就是过滤链filterChain实例(兵),每个检查的科室就是过滤器filter(营盘),到一个科室,你把单据给医生处理,处理好,你就做下一项。可以看到单据是轻量的业务对象,科室是重量级的配置对象。科室不持有单据对象,而是每次收到进行处理,处理好就结束了。

    再回到web应用中的filter,doFilter就是过滤器中要实现的方法。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) 从中可以看到,这三个参数都是外部传入的业务对象,每一个外部的请求,这三个都是不同的实例。配置对象一般不持有业务对象,而是传过来,处理好就结束了。在doFilter中,会调用传入的业务对象filterChain的doFilter方法。实现就是让单据做下一个过滤,也就是让单据做下一个体检。filterChain.doFilter(request, response);

    我们知道,单据是不可能自己做体检的,doFilter中的方法只是找到这个单据中记录的下一个科室,让这个科室真正再做doFilter。科室虽然不会持有单据,但每一个单据必须引用科室对象。通常的做法是单据引用一个医院对象,医院对象中必然有所有科室的容器。每个单据记录下自己项目的科室的索引,这样每个单据从医院对象中的科室容器中找到科室,相当于你在医院的大楼科室布局图上找到科室一样。每个单据都是一个业务对象,各不相关,也许包含的科室不一样,也许项目一样,但当前已经完成的项目不一样。比如大家一起去体检,表格都一样,有的人检查的快,有的人慢。




图中:厂房、工具间、5个标号的设备都是单例,都直接或者间接的引用着。每个业务单据上的记录都不一样,没处理过的都是00000,中间处理的可能是11000,后面都处理好的是11111。

    具体说一下我设计的系统中的对象:
首先有一个厂房,里面有容纳过滤器的MAP,都是spring加载的单例(默认都是单例),还有一个数组对应过滤器通过afterPropertiesSet加载,方便通过索引找到过滤器。

//厂房对象
@Component
public class TaskContainer implements InitializingBean {

	public Processer[] porcesser=new Processer[8];//过滤器索引-设备编号
	
	@Autowired
	private Map<String,Processer> processerMap;//所有的过滤器-厂房中的设备

	@Override
	public void afterPropertiesSet() throws Exception {
		//顺序排序
		porcesser[0]=processerMap.get("processerA");
		porcesser[1]=processerMap.get("processerB");
		porcesser[2]=processerMap.get("processerC");
		porcesser[3]=processerMap.get("processerD");
		porcesser[4]=processerMap.get("processerE");
		...
		...
		...//后面继续加,与数组个数一样
	}

	dealBizInfo(BizInfo bizInfo){
		ProcesserChain processerChain = new ProcesserChainImpl(TaskContainer.this, bizInfo);
		processerChain.setStartIndex(0,5);//从0开始,到5号。对应过滤器的索引号
		processerChain.processOrder();
	}
}




    再就是厂房里的设置:过滤器。它也是单例对象,实现相同的接口,加载处理数据需要的工具对象。接口的实现中两个参数,一个是要加工的数据对象,一个是过滤链对象,这两个都是业务对象。
    厂房既然要加工数据,就有这个一个方法, 给过来的数据生成一个单据-过滤链条,主要语句有:
@Component
public class ProcesserA implements Processer{

	@Autowired
	Tools tools;//过滤器自己有的工具。各种刀枪剑戟 斧钺钩叉工具。

	@Override
	process(BizInfo bizInfo,ProcesserChain processerChain) {
		//进行自己的处理
	
		tools.deal1(bizInfo);
		tools.deal2(bizInfo);
		tools.deal3(bizInfo);
		...
		...
		...
		...
		processerChain.processOrder();//最后交给过滤链,它会用下一个过滤器处理
	}
}


    接下就是过滤链对象,不让spring管理了,或者是prototype也可。来一个业务new一个。
它内部要持有厂房对象,内部要有一个int的索引,记录当前处理就什么位置。当然内部还要持有业务数据。
public class ProcesserChainImpl implements ProcesserChain {
	private TaskContainer taskContainer;
	private BizInfo bizInfo;
	private int processIndex=0;//
	private int processIndexEnd=4;//

	@Override
	processOrder() {
	  next().processOrder(bizInfo,this);//获取当前索引的过滤器进行处理
	}
	private OrderProcesser next(){
		return taskContainer.porcesser[processIndex++];//从厂房中拿到对应索引的过滤器,索引号+1.
	}

	//设置开始与结束索引
	@Override
	public void setIndex(int startIndex,int endIndex) {
		// TODO Auto-generated method stub
		processIndex=startIndex;
		processIndexEnd=endIndex;
	}


    processerChain.processOrder()方法就是开始处理数据了,过滤链(业务对象)肯定要引用厂房对象(直接引用很多工具对象,会显的有些乱。如果有工具容器,可以引用它),这样从厂房中拿到索引对应的设备(配置对象)进行处理,索引号加1,设备处理中会收到数据与过滤链两个参数,处理好,再调用传入的过滤链的方法,又会找下一个设备,再把数据与自己传进入...链条就这样循环启动起来了。

    与传统的filter不同,我进行了改进。我也配置了多个过滤器,但业务处理的过滤链根据实际并不都是从头到尾,有开始与结束的索引。如果中间出错了再启动,可以从断掉的地方再配置。一部分业务用前面几个过滤器,后一部分异步任务用另外几个过滤器。如果想更灵活,可以配置,这个业务使用13567过滤器,那个业务使用24678号过滤器。

四.开发微核心结构,对象外部接口实现的加载不同的实现

    最近做的一批小项目,因为核心功能是一样的,不同的部分都用接口。简化的说,就是抽象化开发了接收数据,外部持久化接口,处理数据接口,结果汇总,再次结果持久化接口这样的一个过程。

    这种样子的工具非常多,比如JBPM工作流工具,比如shiro,spring security权限控制,他们都实现了一个基本的公共的功能,但有些需要使用者开发接口的实现类。

    首先我这个微核心模块与spring没有半毛钱关系,但接口的实现,由于多数是web项目,就与spring有密切关系了,就拿持久化来说,通常service、dao由spring管理。

    如何对接这样的微功能模块呢?还记得有一个原则,高内聚,低耦合。我在使用这样开发好的模块时,会专门设计一个spring的类,来持有(或者叫对接、管理、holder)这个微功能模块中的厂房,如同你的公司买了另一个公司,会安排一个高级人员专门去管理那个公司。这个微系统通常自己有一个静态的态来管理它的启动,管理它要传入参数与实现类,还要调用静态方法init(),让这个工厂运转起来。这个静态类如同那个公司的负责人,派来的人员,只要对接公司目前的负责人就可以了。

    通常我的做法是这样:spring的对接类(高级人员),会注解引用一些需要的接口的实现类。它管理静态类时(通常是afterpropetyset方法中),会把接口实现类通过模块静态类的方法传进去。如同你自己带来的几个人去接管,通过原负责人安排这些人到关键的、缺少的岗位上去。这样,接手的公司就可以正常运转下去了。

五、总结

    上面介绍了对象的引用、相互引用、配置类的多边引用与业务类的关系。更进一步分析了类组成的模块之间如何进行关联的经验。

    回顾起来,我设计系统,貌似总喜欢拿出生活中的场景来对应,这样让系统中的对象之间的关系更合理。我认为生活中的制度设计、组织设计可以用软件来模拟,也可以给软件设计以启发。


注:目前对过滤器模式又进行了改进,除了之前配置开始结果索引外,考虑到失败情况描述,在filterChain中增加处理信息字段。当某一个处理器处理失败,会写入失败码与描述,成功也会。
  • 大小: 203.9 KB
  • 大小: 473.1 KB
  • 大小: 282.7 KB
分享到:
评论

相关推荐

    Java设计模式之监听器模式实例详解

    监听器模式是Java设计模式中的一种行为型模式,主要用于监听某些事件的发生,并在事件发生时自动执行预定义的操作。在实际开发中,监听器模式可以用于多种场景,如UI事件处理、事件广播、异步通知等。 在监听器模式...

    java监听器和过滤器详解

    监听器在Java Web开发中扮演着非常重要的角色,主要用于监听特定容器事件的发生,比如服务器对象的创建与销毁等,并根据这些事件做出相应的处理。它的工作原理类似于事件驱动模型,其中事件由容器触发,监听器负责...

    过滤器和监听器的使用与区别

    在Java Web开发中,过滤器(Filter)和监听器(Listener)是两种非常重要的组件,它们主要用于增强应用程序的功能和管理应用程序的状态。本篇文章将详细解释这两种技术的使用、配置及其区别。 首先,我们来了解过滤...

    java监听器的实现和原理详解

    在Java中,事件监听器的实现可以通过接口和类来实现。例如,我们可以定义一个事件监听器接口,包含事件处理方法,然后在事件源中注册事件监听器。当事件源触发事件时,事件监听器将被回调,执行相应的事件处理方法。...

    关于过滤器和监听器的使用模板

    在Java Web开发中,过滤器(Filter)和监听器(Listener)是两个非常重要的组件,它们主要用于增强应用程序的功能和管理应用程序的状态。以下是关于这两个概念的详细说明。 **过滤器(Filter)** 过滤器是Servlet...

    javaEE(上下文_监听器_过滤器) ppt

    Java EE(Java Platform, Enterprise Edition)是用于构建企业级分布式应用程序的框架,它提供了一系列标准接口和组件模型,包括上下文、监听器和过滤器。这些概念是Java EE开发中的核心组成部分,对于理解和优化Web...

    java 过滤器和监听器 java 过滤器和监听器

    java 过滤器和监听器

    java中监听机制,以及观察者设计模式

    Java中的监听机制与观察者设计模式是编程中重要的概念,它们在软件开发中扮演着关键的角色,尤其是在构建可扩展和可维护的系统时。这里,我们将深入探讨这两个主题,并通过实例来阐述它们的工作原理和应用。 首先,...

    jsp/servlet中过滤器和监听器的区别

    理解并熟练使用过滤器和监听器对于开发高质量的Java Web应用至关重要。它们可以提高代码的可维护性、可扩展性和安全性,同时也能帮助开发者更好地管理应用程序的状态。在实际开发中,应根据需求选择合适的技术,以...

    java一个监听器的例子

    在实际应用中,监听器经常与其他设计模式结合使用,如观察者模式(Observer),提供更灵活的事件处理方式。通过熟练掌握Java监听器机制,开发者可以创建更加响应用户输入的、交互性强的应用程序。 在提供的压缩包...

    过滤器和监听器的使用

    总的来说,过滤器和监听器是Java Web开发中不可或缺的工具,它们增强了服务器端的处理能力,提供了更丰富的扩展点,使得开发者能够更好地管理和控制Web应用程序。理解和熟练掌握这两者,对于提升Java Web开发技能至...

    java核心技术-java中监听器和过滤器的使用笔记

    Java核心技术中的监听器和过滤器是Web开发中的关键组件,主要应用于Servlet容器中,用于增强应用程序的功能和控制请求与响应的处理流程。本篇将详细阐述Java中的Filter(过滤器)及其使用方法。 1. **Filter(过滤...

    用java实现监听对象的属性变更

    (1)创建测试页面,在chapter08项目的WebContext根目录中,编写一个testattribute.jsp页面,以观察各个域对象属性事件监听器的作用。 (2)在cn.itcast.chapter08.listener包中,编写一个名为MyAttributeListener的...

    过滤器和监听器教程(java)

    在Java Web开发中,过滤器(Filter)和监听器(Listener)是两个非常重要的概念,它们主要用于增强应用程序的功能和管理应用程序的生命周期。本教程将深入探讨这两个核心组件,以帮助开发者更好地理解和应用它们。 ...

    servlet中的过滤器与监听器

    在Servlet技术中,过滤器(Filter)和监听器(Listener)是两个非常重要的概念,它们帮助开发者实现对请求和响应的拦截、处理以及管理应用程序的状态。 ### 1. Servlet过滤器 **过滤器** 是Servlet API提供的一种...

    JavaWeb中的监听器与过滤器

    ### JavaWeb中的监听器与过滤器 #### 一、监听器(Listener) 监听器是Java Web应用程序中的一个重要组件,主要用于监听容器中特定事件的发生,并作出相应的反应。在Java Web开发中,监听器主要用来监控应用中某些...

    过滤器与监听器

    在Java Web开发中,过滤器(Filter)和监听器(Listener)是两个非常重要的概念,它们主要用于增强应用程序的功能和管理应用程序的生命周期。本篇将详细阐述这两个知识点。 **过滤器(Filter)** 过滤器是在...

    java监听器练习

    Java中的监听器机制是基于观察者模式的设计模式之一,广泛应用于图形用户界面(GUI)应用程序中。 #### 二、监听器的基本组成部分 监听器通常包括以下几个部分: 1. **事件源(Event Source)**:触发事件的对象,如...

    关于监听器Listener和过滤器的小demo

    在Java Web开发中,监听器(Listener)和过滤器(Filter)是两个非常重要的概念,它们主要用于增强应用程序的功能和性能。下面将详细讲解这两个概念及其应用。 ### 监听器(Listener) 监听器是实现特定接口的Java...

    java监听者模式三个实例

    在这个"java监听者模式三个实例"中,我们将深入探讨如何使用监听者模式来实现事件驱动的编程。 1. **监听者模式的基本概念** - **观察者(Observer)**:即监听者,它定义了接口用于接收被观察者的通知。 - **被...

Global site tag (gtag.js) - Google Analytics