题外话:为了不再误解,关于造轮子的事情在本篇开头再次重点提出,如果您觉得再造轮子的人是傻瓜,那直接无视我以及我的附带品好了.本文的重点并不是做了一个验证框架,真要如此,直接给出代码不就结了,或者直接来篇如何使用DataAnnotations即可,何必长篇大论来一通,如果认真看了本文就可以知道本文是讲解了如何使用TDD的方法来实现一个验证框架,同时尽可能做到通俗易懂,当然,这并不是说本文造的轮子就没有价值了,别人的总是别人的,验证框架并不是一个很复杂的东西,一个人做出一个完善的也不是什么难事,也许在某些时候土炮就比洋炮好用也说不准,最后,希望各位手下留情.
    说了一通废话,下面开始正文了,本篇的重点是解决前篇的代码灵活性问题,前一篇我们对实现了两个验证属性,但是确遇到了新的问题,方法中代码量的激增以及死板的验证方式无法让我们灵活的扩展该框架,穷则变,变则通,我们不得不想办法解决这个问题,从目前的代码看,实体的Validate方法明显有问题,它的责任明显太多,势必要对其进行重构,要把它的责任分离出去,如何分离呢?
    我们完全可以这样考虑,现在的验证属性仅仅申明了验证参数,而且如果有很多属性参数也会不同,验证的模式也各不相同,那为什么不让验证属性自食其力,自力更生呢?自己的限制,自己验证多好.因此考虑扩展验证属性的功能,既然验证是一种契约,一种公共行为,我们免不了设计一个接口来负责这部分的内容,考虑下面的接口:

    这样一来我们就可以在xxxAttribute中实现相应的验证逻辑了,首先确定新的验证代码,对3个属性进行全面验证测试:

    然后我们开始重构RangeAttribute和RequiredAttribute类,下面的图片分别展示了两个属性中的验证逻辑


    最后修改Student部分的验证方法,来通过调用xxxAttribute的Validate方法实现各个属性的验证

    然后执行测试代码-通过,很庆幸我们的重构完成的很好,这样一来,只要是实现了IValidationFIlter的验证属性都可以自动的进行验证了(到此为止的代码请参考Leven.Validate04).
    下面考虑另外一个问题,现在我们的验证方法是写在Student实体中的,不妨考虑如果我们有另外一个Teacher实体那该如何?难道又要在Teacher实体中把这个方法copy过去么?这显然不是一个好办法,我们不得使用一种方式将这段代码提取出来,这样一来可以考虑以下两种方式:
1. 既然每个实体都要有这个方法,则可以对实体对象进行抽象,在其顶端实现公共基类,在基类中实现该方法
2. 完全不修改实体对象,另外建立方法(静态方法??扩展方法??)来进行验证
    对比以上两种方式,可以预见,第二种方式能建立更广泛的验证,也就是说,它可以对Object进行验证,当然前提是该Object中有属性添加了验证Attribute(没添加也不要紧,这样验证永远都会成功),因此,使用第二种方式的验证可以用在任何对数据效验的环境下(实际上, DataAnnotations等不限场合的验证框架都使用这种方式)而第一种方式看起来会对实体本身进行要求,必然产生了局限性,然而,我们现在要考虑的是表单实体,也就是说可能在必要的时候能和Asp.Net MVC框架能够整合在一起,这本身就是一个限制了,因此,第一种方式也不失为一种不错的选择,这样一来,我们就限定了只有部分我们需要的实体能享受该功能.同时如果以后在和MVC框架整合的时候不需要考虑更多的情况,所以目前决定了,就使用第一种方式了.
    首先仍然是确定接口,一个必须的IValidationEntity接口,然后针对该接口必须有一个默认的实现ValidationEntityBase,具体实现步骤如下:
1. 新增IValidationEntity接口,接口中包含一个Validate方法
2. 新增一个ValidationEntityBase类,实现IValidationEntity接口.
3. 将Student的Validate方法代码搬到ValidationEntityBase的Validate方法中
4. 新建单元测试,测试代码和先前一致
5. 开始测试,保证测试通过
    通过这几步,我们成功对实体进行重构,如果我们新增任意实体,只要继承自ValidationEntityBase,就可以享受到验证的好处了,在项目Leven.Validate05中,可以看到完成后的源代码,同时,实现了新的实体Teacher,并进行了测试.
    小结:我们回过头来看看框架一步步的重构过程,从目前来看,前面几次重构都是针对扩展性进行的,这正是框架和普通程序的根本区别,框架考虑的一般化,因此,我们一步步的实现了几个目标:
1. 第一次完成的代码,就实现了实体的属性中可以有任意多个验证Attribute
2. 第一次重构,实现实体的每个属性都可以有任意多个验证Attribute
3. 第二次重构,实现了实体的每个属性都可以有任意多个目前支持的两种验证Attribute
4. 第三次重构,分离验证职责,加入验证Attribute扩展功能,,使得实体的每个属性都可以有任意多个实现了IValidationFilter的验证Attribute
5. 第四次重构,转移验证方法,加入IValidationEntity接口,使得任意实现IValidationEntity接口的实体的每个属性都可以有任意多个实现了IValidationFilter接口的验证Attribute.
    到现在为止,才算是真的有点像框架了,上面的5次编码过程,虽然说起来比较绕口,但是仔细看来,正是将功能一步步泛化的过程.真正实现了验证框架的两个重要目标:1.能扩展规则,2.为需要验证的对象提供验证服务,同时区分哪些是需要验证的对象.
    到目前为止的类图如下:


    现在看来,框架似乎可以满足我们的要求了,那是不是已经完美了呢?当然不是,如果真要在实际中使用,还有很多其他的因素要考虑,首先,我们在验证Attribute定义了错误信息,但是目前我们验证完成之后只得到一个bool值,没法得到相对应的验证信息,其次,目前框架使用的是反射来对数据效验,然而反射的效率总是人们觉得不爽的地方,在下一篇中,我们将着重解决这几个问题.
    最后给出项目文件:/Files/leven/LevenValidateLibrary02.rar

posted on 2009-03-27 10:09  Leven  阅读(4288)  评论(23编辑  收藏  举报
CopyRight 2008, Leven's Blog xhtml | css
Leven的个人Blog