posts - 48, comments - 139, trackbacks - 2, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理
    自从《颠覆传统-面向对象的设计思想(序章)》发布出来后看的朋友和评论的朋友很多,有说好的,也有说不好。当然也有很多朋友在文章的评论中发表了自己的见解,在这里我就一些比较典型的评论做一下解释。
  • 来自名为wanghualiang 的评论
很佩服楼主的发散型思维。但是远远还没到颠覆传统的地步。
这里谈谈我的观点,
面向对象设计时完全从接口来描述对象本身的特性是不是有问题。
从鱼是不是可吃应该只能作为其一个属性来辨识,
Class Fish
{
public bool IsEatable;
}
当客户想吃这条鱼的时候,IsEatable
=true;如果是河豚的话就是 False了。
当然有许多种不确定的因素,在可吃不可吃之间。那我们应该
[Flags]
Enum Eattype
{

DeliciousEate,
//美味
Distasteful,
Barbed,
..
}

Class Fish
{
public Eattype eattype;
    我想wanghualiang 的评论代表了相当一部分朋友的看法,从传统的面向对象思想(或者说普遍接受)的观点来看这样做是没有问题的,甚至还被作为了Demo写入了很多的面向对象的教科书。但是实际上这种看法是存在问题的,至少我个人是这么认为的,首先我们需要考虑的问题是:鱼自己能不能决定自己能不能吃,能不能决定自己好不好吃?应该是不能吧,决定鱼能不能吃,好不好吃的应该是吃鱼的对象对吧。也许从普通人的角度来看河豚是不能吃的,但是从高明的大厨或者资深的老饕的角度来看河豚就是无比的美味了,这也是我在序章的最后专门添加一幅图片重点解说对象行为的原因。
    话说回来,既然鱼不能决定能不能吃、好不好吃,也就是说明能不能吃的行为不是有鱼能够决定的,那么也许有人会问那为什么要实现IEatable接口呢,和直接做一个属性不是一样吗?这个问题问的非常的好,确实既然鱼不能够决定自己能不能吃、好不好吃,那么为什么鱼要实现IEatable接口呢。其实,在Fish上实现IEatable接口完全是出于使用方便性和接口的层次(后续的文章中会重点讨论这个问题)来考虑的,完全面向对象的搞法应该是有另外一个对象来鉴定这个鱼是否能吃、好不好吃的(这也是基于设计的平衡来考虑的,可以参看开放-封闭原则)。在这个地方使用接口和属性本质上没有什么差别,但是一旦鉴别鱼能不能吃、好不好吃的鉴别方式(实现方法)发生变化的时候,使用属性的方式就难以扩展了,只能修改代码了,但是使用接口的好处是我可以使用其它的方式补救,例如做一个实现IEatable接口的装饰对象来装饰鱼对象。
    另外,导致需要鱼对象实现IEatable接口的原因可能是出于接口隔离原则的考虑,如果使用属性来辨别鱼是否能吃,必然使用的地方就依赖鱼对象了,提高了系统的耦合性。示意代码如下:
 1 '检索是否可以吃的食物
 2 Public Function GetEatableFish(ByVal foods As IEatable()) As IEatable()
 3 
 4     '用于保存列表
 5     Dim tempList As New ArrayList
 6 
 7     '循环的检索
 8     For Each item As IEatable In foods
 9 
10         '判断是否可以吃
11         If item.IsEatable Then
12 
13             tempList.Add(item)
14         End If
15     Next
16 
17     '返回结果
18     Return tempList.ToArray(GetType(IEatable))
19 
20 End Function
21 
22 '是否可以吃接口
23 Public Interface IEatable
24 
25     '是否可以吃
26     Function IsEatable() As Boolean
27 
28 End Interface
   软件设计的时候没有一味的好,也没有一味的差,任何事情都有其两面性,这个是需要取舍的,我们能够做到的事情就是让设计可控,如果设计失控了,那就全部完蛋了。话说回来,如果能够确认当前的系统中评判鱼能不能吃的标准不会发生改变,把这个不会发生改变的东西集成到鱼对象中是完全可以的,在具体的实现上用属性来实现也是一个非常不错的搞法。
  • 来自名为 Anders Liu 的评论
嗯。。。建议你在多想想再继续写。

比如这个:
public class Goby : IFish, IClimbable, IEatable
我认为这样比较好:
public class Goby : Fish, IClimbable, IEatable

看到区别了么? 
    至于Anders Liu 的评论应该与wanghualiang 的意见基本上是一致的,如果我没有理解错误的话。我们引入一个Class的时候需要考虑的是引入这个Class的目的,如果没有任何目的的引入一个类或者是仅仅简单的为了封装一个方法来引入一个类是不可靠的,后面我会写一篇随笔来专门讨论类和接口。


Feedback

#1楼   回复  引用  查看    

2007-08-01 12:15 by 金色海洋(jyk)      
弱弱的问一句,面向行为和面向过程的区别是什么呢?

要说分类嘛,我觉得是对函数的分类,那些函数是一类的,或是相关联的可以放在一起,放在一起了就成了Class了,然后呢Class又多了起来,怎么办呀?

于是呀,继承(派生)、多态就出来了。

为了更好的管理和使用继承(派生)、多态,就出来了一大堆的模式。

我的原则:用最简单的方法解决复杂的问题!

#2楼   回复  引用  查看    

2007-08-01 13:45 by Anytao      
作者的观点很有特点,不过在此提出点异议。
其实Anders Liu 与wanghualiang的意思不是完全一致,其实他们的表明的只是在实际设计中应该着眼于具体情况,而不是以Act-As一个方向看世界。例如:
public class Goby : IFish, IClimbable, IEatable;
Goby aGoby = new Goby();
那么Goby的属性、状态该如何体现呢,难道aGoby只有行为不成,当然我们可以在Goby中实现具体的属性和状态,但是如果又有一个
public class Whale: IFish, IEatable;
Whale aWhale = new Whale;
那么aWhale的属性难道还得再实现一次?
面向对象肯定不是这么做的,因为完全可以Goby和Whale的共同特性封装到共同的基类Fish,所以,以
public class Whale: Fish, IEatable;
实现在这种情况下更具有设计的思路。
面向对象的核心思想是封装变化,所以不管是IS-A还是Act-AS,关键还要看具体分析,不可一概而论。

#3楼   回复  引用    

2007-08-01 14:37 by 古巴[未注册用户]
个人认为OO的最终目的不是把现实世界的一切转换成一个个的class,这不现实。现实中的一个事物,在不同的场景和需求下,即便是同一个设计者也很可能得出不同的设计来。而且我们OO无非就是为了便于系统的开发、维护和扩展,所以为了这个目的,到底是面向对象还是过程还是服务,如何面向,应该是具体问题具体分析(经典废话),不存在绝对的标准、规范,甚至有时候过程一把也还是很方便的。

#4楼   回复  引用  查看    

2007-08-01 15:37 by xiao_p      
@古巴
非常同意

oo难道真的要和真实的世界挂钩吗?
其实,个人理解class就是一个尺度,一个field和method的容器,它不过是我们程序复用的一个单元!

#5楼   回复  引用    

2007-08-01 17:01 by losang[未注册用户]
【鱼自己能不能决定自己能不能吃,能不能决定自己好不好吃?应该是不能吧,决定鱼能不能吃,好不好吃的应该是吃鱼的对象对吧】

作者傻的不行,这是业务逻辑负责的范畴,不要搞混好不好,真是费劲

#6楼   回复  引用  查看    

2007-08-01 18:25 by 东吴居士      
同意Anytao
  面向对象的核心思想是封装变化,所以不管是IS-A还是Act-AS,关键还要看具体分析,不可一概而论。

#7楼   回复  引用  查看    

2007-08-01 23:23 by 静水≈深流      
关注一下

#8楼   回复  引用    

2007-08-01 23:54 by dw[未注册用户]
好....

#9楼   回复  引用  查看    

2007-08-02 00:06 by thh      
同意楼主的意见。如果想吃其他的东西了,只要检查是否IEatable就可以了,比挨个检查IsEatable属性更通用,也更明了。

#10楼   回复  引用    

2007-08-02 09:10 by cnblogs[未注册用户]
【同意楼主的意见。如果想吃其他的东西了,只要检查是否IEatable就可以了,比挨个检查IsEatable属性更通用,也更明了。】
如果这样的话比使用属性有什么好处吗?

#11楼   回复  引用  查看    

2007-08-02 10:08 by 土星的狗狗      
我们引入一个Class的时候需要考虑的是引入这个Class的目的,如果没有任何目的的引入一个类或者是仅仅简单的为了封装一个方法来引入一个类是不可靠的,后面我会写一篇随笔来专门讨论类和接口。

非常精辟的一句话,我会留在心中。
其它就是这么一回事儿,不管是要做到面向对象也好,面向行为也好,总的而言一切还不都是对象嘛,只不过是对象换了个具体一点儿的名字。
我们写一个类就是为了抽象出一个事物,是对象也好,全是行为也好,解决了什么问题,怎么解决的,是不是要知道,这条鱼能不能吃它自己是决定不了的,为什么不把这个能吃的判断放在吃它的生物的身上,或者做为一个吃的标准设为中间层,当去吃的时候再去用这个吃鱼的生物的判断水平去做出决定不是更好吗?
非常有点复杂,但至少更易于理解。
能不能吃用接口来实现是非常正确而用属性不可替代的,举个最简单的例子,猫跟人吃鱼时的判断准则就有大不相同的地方,所以需要在不同的吃鱼者吃鱼时做不同的判断。

#12楼   回复  引用  查看    

2007-08-02 10:42 by Anders06      
很赞lz的思维, 然更严重地同意Anytao说法.

LZ的想法还是过于理论化,大有忽视需求之说.
public class Whale: IFish, IEatable;
还是
public class Whale: Fish, IEatable;
应该是需求确定, 接口跟类的区别还是挺大的,两者能做的不能做的还是有些区别,实际上偏向于哪一个还是得由需求来说.

设计之道实为按需设计!

#13楼   回复  引用  查看    

2007-08-02 10:46 by Anders06      
还有点忘记说了, 编程里的模型未必能完全对的上现实中的模型,不必苛刻追求

#14楼   回复  引用  查看    

2007-08-02 14:41 by 非我      
角度问题而已,单纯的OO一个静态的世界,IS A是正确的,而LZ关注的是特定的、动态的情况,这时IS A是不怎么适用了,但并不是IS A有什么错

#15楼   回复  引用    

2007-08-02 16:34 by zhou[未注册用户]
IEatable接口?还是很难理解为什么这么做

#16楼   回复  引用    

2007-08-03 10:55 by Nick[未注册用户]
其实,我个人觉的,设计是一个渐进的过程,不可能一步到位的。如果开始就考虑的过度了,那么,设计过度应该也不是件什么好事吧?
其实,如果做设计的人对这些东西不了解到话,那么,肯定做不出什么好的设计
但是,如果完全照搬也绝对是个问题
这个时候,设计的经验就能体现出来
系统是重构出来的,呵呵

#17楼   回复  引用  查看    

2009-06-15 16:41 by 杜宏雷      
v,好.~~



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 838812




相关文章:

相关链接: