代码改变世界

“九种不够面向对象的对象“的在实际项目中的合理运用

2009-07-04 19:59  Ivony...  阅读(3282)  评论(52编辑  收藏  举报

本文可以视为对http://www.cnblogs.com/DesignPatterns/archive/2009/07/04/nine-non-oo-o.html文中观点的反面意见。

 

在引用的这篇文章中,作者指出了九个其认为“不够面向对象”的对象。而本人一直不喜欢不是面向对象或者不够面向对象这样的提法,在本人看来,所有的这些对象不过是因为其不够饱满,而在实际的项目设计中,根本没有必要要求所有的对象都是饱满的。对象的饱满程度与对象的设计粒度有关系,简单的说,如果是一个非常简单的项目,比如说输入一个数输出某种算法的结果这样的小练习,一个对象负责交互、计算、计时等等工作是没有任何问题的。但是如果你是做一个计算器,那么你把这些东西都写在一个类型里面,粒度就明显过大了。

仍然用生物界来做例子,将对象比喻成细胞,那么对于原生生物而言,只需要一个细胞(一个对象)就够了,这个细胞可以自行增殖、吸取养分,甚至可以抵御外敌和自由行动。但是对于高级生物而言,则需要大量的细胞协同工作,这些细胞可以是没有行为的(骨骼细胞),也可以是不能增殖的(脂肪细胞),但这些都不影响它们在存在的合理性。

 

 

废话不多说,下面随便指出几个所谓的不够面向对象在设计中的合理运用:

 

1、贫血对象,事实上就是退化成数据结构的对象,对象可以视为是数据结构的扩展,对象=数据+行为。如果一个数据自己没有行为可不可以呢?没有道理不可以的,比如说狗会叫,石头会叫么?石头难道就不是对象了?没有行为的对象最著名的如string,另外如Uri,所有的基元类型也可以视为是所谓的贫血对象。不要以为这样的对象就与OO没有关系,没有石头用什么去打狗呢?说设计是不是合理,取决于这个东西是不是丢失了本来应该有的行为,而不是说没有行为的都不是Object了。

2、管理者对象,其实就是抛弃了数据结构只剩下方法退化成方法组的对象。同上面的对象的存在是合理的一样,只有方法组的对象存在也是合理的。而且非常重要,因为方法是多态的。绞肉机需要自己有肉么?刀子需要自己有苹果么?那么方法组为什么一定要带上数据呢?比如说我们定义一个刀子类,显然这个刀子是不需要自己有苹果的,没有人会new 刀( 一个苹果 )吧?而只可能是:一把刀.切( 一个苹果 )。而且,我们可以方便的class 花刀 : 刀,利用多态的特性来使得我们可以把苹果切成星型、三角形等各种形状。你能说这不是OO么?

3、储柜对象,事实上是一个强类型的Dictionary,这种对象存在的意义与Dictionary存在的意义是一样的(或者说就是1的情况)。既可以作为数据打包的传递,也可以作为一个适配器来对某个抽象的、不存在的东西进行控制。作为Dictionary的用途就不说了,说说适配器的用途。比如说DOM模型中的对象,大部分对象的属性都是R/W的,这样的对象实际上是文档模型的一个适配器,通过修改对象来修改文档。这又有何不可呢?

4、多管闲事的对象,虽然这大多数情况下是抽象的问题,但在一个优秀合理的设计中这种情况也并非不存在。就那篇文章的作者所举的例子而言,完全属于抽象的问题,Pet怎么可能都会CatchRat?这是很滑稽的。但一个类型将继承的方法屏蔽这种情况却“不都是”抽象的问题。比如说我们设计一个类:猫,那么猫一定会吃东西、能跑跳。但是残疾的猫和昏迷的猫呢?那么它们不是猫么?显然它们也是猫,但是并不是所有猫都具备的行为它们都有,这样的情形,就必须在派生类中屏蔽基类方法来实现。而不可能是我们将猫去继承于残疾猫。继承关系的最大原则是抽象关系,具体类型继承抽象类型。其他原则是帮助我们把握抽象关系的方法,而不是必须遵循的原则。

最后关于第8点谈谈,没有专属自己的数据,没有专属自己的行为,就不要一个类型这样的说法显然是不靠谱的,是不是需要一个类型,最重要的是看这个类型有没有意义,而不是这个类型有没有独特、专有的东西。类型的首先在于类型本身而不在于其成员。或者说,正确的设计是先确定类型,然后再设计其成员,而不是将成员列张表然后归纳出几个类型。比如说我们设计一个正方形类,继承于矩形,请问这个正方形是有什么它有而矩形没有的呢?但是这个类型是有意义的,比如说我们有些方法只能对正方形进行操作,就不应该接收一个矩形对象,然后判断这是不是一个正方形。