现在的位置: 首页 > 综合 > 正文

从抽象到模式——面向对象之旅(二)、代码的坏味道

2013年03月07日 ⁄ 综合 ⁄ 共 2248字 ⁄ 字号 评论关闭

   在上一节中,我们设计了一个过滤器的抽象类,并且在客户代码中通过抽象,很好地利用了类的接口。瞧,抽象是多么地强大,多态是多么强大!天是蓝的,水是清的,生活真是美好啊(Copy某位大师的口吻^_^)。

  但是,不要高兴太早,问题来了。现在,我们有一个新的需求:

  为了提供更好的扩展性,要求每个过滤器除了提供一套默认规则之外,还要允许客户(即系统的使用者)可以根据需要对规则进行扩充,当然,用户自定义规则是和默认规则分开保存的。

  呃,这是哪个家伙出的馊主意?!!

  

  不过还好,变化不是很大。不就是把规则分为默认规则和自定义规则吗?这有何难!

  看,我只需要增加两个函数就可以了,GetDefaultRules()读取默认规则,GetConfigRules()读取自定义规则,然后把InitRules()当中读取规则的地方用这两个函数替代。

  不过子类还是要辛苦一下了,把原来的InitRules()函数名替换成GetDefaultRules(),然后再加入新的GetConfigRules()。

 

  OK,一切搞定!代码看起来仍然不错。真的是这样吗?

  现在到了搬“教条”的时候了,翻开Bob大叔的《敏捷软件开发》看一下——单一职责原则。我们的Filter类是一个数据检查类,还是规则读取类,还是两个都有?如果是数据检查类,那么看,怎么读取规则的接口比数据检查的接口还要多?如果我是代码的阅读者,我更愿意相信他是一个规则读取类。事实上,恭喜您中奖了,这个类集数据检查和规则获取于一身,已经违反了单一职责原则。

  很显然,我们要把两个刚刚添加的,可恶的接口提取出来,形成一个新的类才行。

  慢着,我们不是说不同的过滤器规则不同,保存的形式也不同吗?好吧,看来还要用上抽象,让每个过滤器子类同时再继承RuleReader类。完成后的代码就是下面这个样子,我们的DataCheckFilter类做AuthFilter类同样的处理就可以了:

  编译一下吧,惨了,没有通过。看看哪里出了问题,原来是Filter中的InitRules接口不见了,在PlugIn类中调用Filter的InitRules时就出现了问题。

  等等,这个主意怎么样?我们的过滤器子类不都继承了RuleReader吗,我们把Filter *强制转成RuleReader *不就可以了嘛。

  呃,我可不认为这是个好主意。另外,除了上面这一个问题,这段代码仍然存在着其他问题:

  1)我们刚刚把规则读取接口提取出来形成了一个新的类,目的是为了实现单一职责原则。但是刚刚过滤器子类对RuleReader的继承,不是让我们的功夫白费了。这些丑陋的子类还是职责不明啊。

  2)抛开单一职责不说,从另一个角度分析,这段代码的臭味也不小。继承只有在子类“IS A”父类的情况下使用,在这里我们更应该使用“HAS A”的关系。想一下,过滤器有一个规则读取器,用来读取相应的规则,这样的话看起来还不错。

  3)当我们某一天需要的仅仅是读取AuthFilter的规则,而不需要对数据做检查时,仍然要让AuthFilter调用RuleReader的接口去做这件事吗?当然是不合适的。没关系,到那个时候再派生出一个专门读取规则的子类来不就完了吗?好,让你说中了。与其火烧眉毛了才做,不如现在就派生出来,而且也可以解决我们现在的这一系列问题。

  那么下一步我们要怎么重构呢?先休息一下,下一节我们继续。。。

  

  

抱歉!评论已关闭.