代码检查(5)

5. Feature Envy

Feature Envy,按照Martin Fowler的定义是: 函数对某个class的兴趣高过对自己所处之host class的兴趣。通常的代码检查工具会根据一个类中的方法调用另一个类中方法的次数来判断是否存在Feature Envy。

遗憾的是这个定义是含糊的。Feature Envy做为一种代码现象,如果不能精确的描述和界定其害处,就不能指导我们如何正确处理它,因此我们需要定义什么是有害的Feature Envy。

定义一个有害的Feature Envy,必须从封装说起。

封装是面向对象最根本的原则,泛泛的定义是“把数据和对数据的操作丢到一起就是封装”。这对实践毫无益处,每个人都可以很容易的理解这句话,但仔细想想,过往设计过的对象,有多少是封装良好的?

因为我们不知道封装的根基,这是东方文化中缺乏的东西。大家都知道要封装,但不知道封装什么:

  • 封装权属。
“让上帝的归给上帝,凯撒的归给凯撒。”不要把狗尾巴装到猫身上。当然在实践中总是不那么简单的。在日常生活中,我们常常不知道谁有什么样的权利,不知道某个东西属于谁,不知道谁是管事的等等。长期处于这样的环境中,使人习惯于一种莫愣两可的态度。人都这样了还怎么分的清楚权属呢。但在设计之初记住这个还是有益的。
  • 封装职责。
这是上一个原则的推论。西方人常说的两句话是:It's you business, not mine. None of your business. 西方人认为你的是你的,我的是我的;中国人认为你的是我的,我的还是我的。在我们设计的类中,常常可见就现象就是大杂烩,什么方法都丢到一个类里面处理了。
  • 封装变化。
这也是把不变的东西抽象出来的过程。变化无处不在以具有相对性,把相对不变和相对易变的东西分离开,这个过程是一个抽象的过程,也是对已封装对象的解包和再封装。显然封装变化是从时间的角度来考察对象,结合“软件”的可变特性而来的。如果说封装权属和封装职责在于尊重现实,那么封装变化就是设计过程中真正体现价值的东西。前者意味着照猫画虎,后者才见设计者的功力。

而所谓“代理”,基本上就是封装职责(甚至封装权属,比较少见)和封装变化的结合。

现在我们可以定义一个有害的Feature Envy了:在非代理情况下,对象权属的属性或数据、职责在另外一个对象中,并且被这个对象频繁调用,从而破坏了封装的情形。

借助于代码检查工具,我们可以轻易的找出类之间频繁调用的方法;考虑上述定义,我们可以在恰当的时机进行重构,消除有害的Feature Envy。


feature envy, encapsulation, responsibility, refactor

你可能感兴趣的:(代码检查(5))