deerchao的blog

Be and aware who you are.

软件设计基本原则

1,没有银弹.
2,客户需求是一切设计的根本.
3,使用你的程序的人就是你的客户.别拿同事不当客户,也别拿自己不当客户.
4,判断设计优劣的唯一标准是客户用起来爽不爽.
5,抽象得好与不好全看你的需求会怎么变化.
6,看不惯Book.Save()只说明你没有理解软件是什么.

虽然上面没有提到OO,但是还是特地给一些人补补课:OO的经典含义是"封装+继承+多态",少了哪个也不能叫OO.基于对象和OO不是一回事.

再讲一个基本的逻辑问题:你不能先假设A是OO的,然后又因为A没有用到继承和多态,从而证明OO也能只用封装.

posted on 2007-09-19 18:17 deerchao 阅读(3926) 评论(135)  编辑 收藏 网摘

评论

#1楼  2007-09-19 18:41 金色海洋(jyk)      

不会是对我说的吧。
A是个体,个体不能代表整个群体的,呵呵。
ps:如果是我的哪句话让你产生了这个误解,那么请您原谅。   回复  引用  查看    

#2楼  2007-09-19 18:41 progame      

现在见到设计模式 三层结构 OO
基本绕道而行...

等到代码写多了,自然明白,也自然而然地会运用或体现,否则就算天天挂在口头上讲,那也是白讲   回复  引用  查看    

#3楼 [楼主] 2007-09-19 18:48 deerchao      

@金色海洋(jyk)
当然不是对你讲的了..   回复  引用  查看    

#4楼 [楼主] 2007-09-19 18:56 deerchao      

不是群体个体的关系,而是前提就是错误的--至少是没有证明的.
如果方程式变换时可以两边同时除以0,早就有人证明了1=2,以至任何数都是相等的.   回复  引用  查看    

#5楼  2007-09-19 19:16 RicCC      

把衣服脱了大家都是一样的,XP就搞裸奔,抓住了本质,大家也都乐意欣赏   回复  引用  查看    

#6楼  2007-09-19 19:33 怪怪      

@deerchao
老兄这个第6条很有问题: 软件是早于OO出现的, 总不能说80年代前没有软件吧? 迪杰斯特拉和其它老家伙在60年代就提出了很多类似于后来面向对象的软件设计原则(有些甚至可以说是面向对象的基础), 那时候是没有可以借助的OO的语言或者工具的.

OO的"经典含义", 这个话也太模糊的, 咱们的革命前辈不是说过, 革命不是请客吃饭, 我觉得下定义也是这样, 需要足够的严谨. 比如, 是不是所有的"封装+继承+多态"都是OO呢? 另外如果一个面向对象的设计, 由于需求简单, 用不到继承或者多态, 就不是OO了呢? 在我看来, "封装+继承+多态"只是OO最后出现的典型特征.

既然说到逻辑, 不知道你看了我的几个回帖没有, 一个已经满足你所提出的"封装+继承+多态"的特征的绝对OO的系统, 如果全部展开为只有结构和函数的形式, 他还是OO吗? 实际上任意一个符合你对OO定义的系统都可以还原为这种形式, 只要了解OO的底层实现, 都会知道这一点(园子里也有几篇介绍这个的文章). 那么它是否就不具有"封装+继承+多态"的特点了呢? 在我看来就像因式分解, 换了个形式罢了.

所以我个人觉得, 是不是OO, 关键在于"封装到接口下面/从接口继承/接口可以多态"这三点. 而且这个接口还是严格的指代面向对象概念的接口. 比如WCF现在又有了数据契约, 其实这种数据契约如何定义从广泛意义上来讲也可以看作接口(接口的本质是契约), 但不是面向对象的接口.

P.S.
现在还有看不惯Book.Save()的兄弟么? 毕竟Book这样的契约出现的太有必要了, 否则我的小脑袋真的很难理清那么多东西. 恐怕现在更多的是被Book.Save()乱花渐欲迷人眼的兄弟了吧...   回复  引用  查看    

#7楼  2007-09-19 19:53 怪怪      

不过, 如果没有利用到"封装+继承+多态", 可以说是个残废的OO了..., 但感觉"残废", 比LZ这种绝对化的说法, 更准确一些.

我也被你们带的咬文嚼字了... -___-   回复  引用  查看    

#8楼  2007-09-19 20:07 亚历山大同志      

==========================================
虽然上面没有提到OO,但是还是特地给一些人补补课:OO的经典含义是"封装+继承+多态",少了哪个也不能叫OO.基于对象和OO不是一回事.
==========================================
这段话是你在徐少侠的Post里说的,我这里要再次重申一下,不是咬文嚼字,
OO的经典含义是"封装+继承+多态"这个是没错的,错的是你自己补上去的那一句:
少了哪个也不能叫OO

封装+继承+多态是面向对象设计的原则,但是不是三个都用齐全了,都用上了才叫OO。这是很显然的道理。在徐少侠的Post里我说得很清楚,也不需要重复了。

其他的不说,我就单说这一句。

就我的观点来说你还没有真正理解到什么才是面向对象的原则
面向对象是指 封装+继承+多态 的原则不可违反,而不是指的三种特性必须具备。
如果在一个系统中没有出现多态的应用,是不是就不OO,或者明明很简单的关系不需要继承或者使用多态的特性了却非要去画蛇添足的用上,不然就不叫OO。

所以你的这个观点是绝对错误的。

其余的没啥好说的,软件工程的每本教材上都是这么写的。
但是,我的观点是,既然是用面想对象的语言来做系统,就要尽量使用面向对象的方法,这个和软件工程和银弹都没关系。

  回复  引用  查看    

#9楼 [楼主] 2007-09-19 20:07 deerchao      

@怪怪
第六条我的本意是针对某些人认为"Book"怎么能保存自己这样的看法的.他们觉得只有一个"User"或者其它一个什么东西对"Book"进行保存才更符合现实世界的概念.

"经典"的OO我指的是OO最初被提出来时的定义,后来大家发现只知道使用封装,继承,多态还不够,还需要其它一些指导原则像OCP啊什么的,再后来发展到设计模式时就更提倡"聚合"而不是继承了.   回复  引用  查看    

#10楼  2007-09-19 20:08 WindSnail [未注册用户]

没错,OO只是手段,不是目的。软件开发,质量,成本才是关键。这里面要考虑技术,商业,团队如何协作,当前开发人员的素质。看了前面几篇讨论,真的让我想起了我几年前。实实在在的开发和设计分析做多了,你才会体会到什么才是本质。恕我鲁莽,送大家一句话:如果你不能理解什么是OO,模式也好,架构设计也好,其他什么也好,目的是什么。那干脆,你忘记他们,老老实实写代码,只要努力不让你的代码有bug,让用户用起来不抱怨,让自己有成就感,让自己开发起来感觉不那么累。努力这样去过,过几年自然就明白了。一句话,简单就是美!   回复  引用    

#11楼 [楼主] 2007-09-19 20:10 deerchao      

@亚历山大同志
没有使用多态当然不叫OO,那最多叫"基于对象".
不然VB6为什么被称为基于对象的语言而不能叫它"面向对象"的语言?   回复  引用  查看    

#12楼  2007-09-19 20:12 怪怪      

@deerchao
这是一个匿名的兄弟再另一个帖子里的回复:

book.Save()这里算持久化的操作吧?既然是属于持久化的就没什么OO的说法。

根据DDD的理论这个方法是属于repository的范畴,跟对象本身所属的Entity/Value Object无关

by 一点看法

这个我觉得是要考虑的, 有时book.Save()应该存在, 有时则不太合适.   回复  引用  查看    

#13楼 [楼主] 2007-09-19 20:17 deerchao      

@怪怪
我没有对Book.Save()是否OO发表任何评价,只是说不一定非得写成User.Save(book)这样才能心安理得.

另外,也没有人规定持久化的操作不能由对象自己负责吧?--我倒是觉得只有对象自己最了解自己的数据,所以自己和别的类一起实现持久化操作比较合适.   回复  引用  查看    

#14楼  2007-09-19 20:19 亚历山大同志      

4,判断设计优劣的唯一标准是客户用起来爽不爽.

这条也是我不认同的,软件的客户体验好不好才是用客户用起来爽不爽来决定。国外的软件企业有专门的客户体验部门,而国内的软件企业基本上没有这个部门,所以这个本来应该是有专门部门来完成的任务落到了程序员和架构设计师头上。程序用起来爽不爽很大部分取决于界面和使用流程的优化,花点钱招个好点的美工比一个可以让用户很爽的架构师划算多了。

说白了,架构师的真正责任是让程序高效,稳定的运行,并且具备良好的扩展能里和高度可伸缩的部署特性,这才是一个架构师该做的事情。我们不要将中国特色过度的放大,其实我们很多怪异的观点都是中国特色所带来的,改变现状需要所有的人努力,而不是因为客户要爽了就放任之。

这里有个在中国国情下让用户很爽的方法。招个JS很牛的美工,然后配合售前工程师给客户搭建一个逼近真实系统的原型,改到客户爽了,弄出来客户就真爽了。如果客户经常变需求,那要么就是售前没沟通好,要么就是项目经理无能。

神那,绕过可怜的架构师吧   回复  引用  查看    

#15楼  2007-09-19 20:26 亚历山大同志      

@deerchao
你觉得三者必须具备才叫面向对象的话那只证明你根本就没有真正的理解面向对象。
很早以前在java里很多继承派诟病用接口不OO,到了现在很多理论是要组合优先于继承。现在你敢说少用了某样特性就不OO?
是OO具备封装、继承、多态这些特性,你完全把关系搞反过来了。   回复  引用  查看    

#16楼 [楼主] 2007-09-19 20:29 deerchao      

@亚历山大同志
不管中国的国情是什么样,拿客户的钱,要做的当然就是实现客户的需求.

"程序高效,稳定的运行"这本来就应该是最基本的要求了.
"具备良好的扩展能里和高度可伸缩的部署特性",你往哪里扩展?当然是往客户需要的方向扩展;可伸缩度到底要多高?当然是客户需要的程度了.

其实这句话我还有一个意思,就是写编写非UI界面时,到底怎么抽象,写成几层等等,这些决策以什么标准制定? 标准就应该是使用这些代码的人(自己/同事/..)用得舒服,其它什么OO啊,ORM啊的词汇不应该在第一位考虑.   回复  引用  查看    

#17楼 [楼主] 2007-09-19 20:29 deerchao      

@亚历山大同志
你去搜索一下"面向对象 基于对象"吧.   回复  引用  查看    

#18楼  2007-09-19 20:34 亚历山大同志      

@deerchao
就是搜索了才知道没有任何一条经典理论支持你的观点,不服你就搜索一个有分量的支持你的三个缺一不可才叫OO的出来我看看   回复  引用  查看    

#19楼  2007-09-19 20:46 亚历山大同志      

我给你找了一个
http://www.webopedia.com/TERM/O/object_oriented_programming_OOP.html


A type of programming in which programmers define not only the data type of a data structure, but also the types of operations (functions) that can be applied to the data structure. In this way, the data structure becomes an object that includes both data and functions. In addition, programmers can create relationships between one object and another. For example, objects can inherit characteristics from other objects.
One of the principal advantages of object-oriented programming techniques over procedural programming techniques is that they enable programmers to create modules that do not need to be changed when a new type of object is added. A programmer can simply create a new object that inherits many of its features from existing objects. This makes object-oriented programs easier to modify.

To perform object-oriented programming, one needs an object-oriented programming language (OOPL). Java, C++ and Smalltalk are three of the more popular languages, and there are also object-oriented versions of Pascal.



注意programmers can create relationships between one object and another,是用的Can而不是Must。能和必须是两个概念。   回复  引用  查看    

#20楼 [楼主] 2007-09-19 21:05 deerchao      

@亚历山大同志
在The C++ Programming Language 3rd (Bjarne Stroustrup, 1997)里:
第9页:
Objects of some user-defined types contain type information.
Such objects can be used conveniently and safely in contexts in which their type cannot be deter-mined at compile time. Programs using objects of such types are often called object based.

也就是说,使用不能在运行时分辨类型(意思自然是没使用多态,我想这点你不反对吧)的对象的行为通常叫作"基于对象".

第252页:
I call simple user-defined types, such as Date, concrete types to distinguish them from abstract classes (!ì2.5.4) and class hierarchies (!ì12.3) and also to emphasize their similarity to built-in type
such as int and char. They have also been called value types, and their use value-oriented programming. Their model of use and the "philosophy" behind their design are quite different from what is often advertised as object-oriented programming

明确指出了仅仅使用"具体类型",并不是OOP.

第313页:
Representing a circle and a triangle in a program without involving the notion of a shape
would be to lose something essential. This chapter is an exploration of the implications of this sim-
ple idea, which is the basis for what is commonly called object-oriented programming.

作者虽然没提出多态这个词,但是他所指出的这个使用基类的接口,子类的实现这个事实却是多态,这点你也不反对吧? --作者指出这样编程通常叫作"面向对象编程".   回复  引用  查看    

#21楼 [楼主] 2007-09-19 21:11 deerchao      

你觉得三者必须具备才叫面向对象的话那只证明你根本就没有真正的理解面向对象。
很早以前在java里很多继承派诟病用接口不OO,到了现在很多理论是要组合优先于继承。现在你敢说少用了某样特性就不OO?
是OO具备封装、继承、多态这些特性,你完全把关系搞反过来了。
---------------
我反倒觉得你不知道OO是什么含意.
OO是有其确定含意的,这个含意本身就是"多态". 不是说你觉得什么东西用着好,它就OO的. OO不是"优秀的设计"的同意词,它只是一个中性词,代表一种编程范式而已.
接口当然不OO,--至少不是我一直提到的"经典"的OO.
  回复  引用  查看    

#22楼  2007-09-19 21:29 亚历山大同志      

@deerchao
运行时分辨类型(意思自然是没使用多态,我想这点你不反对吧)
很显然,我反对,运行时分辨类型是语言的能力不是程序的能力,

老实说我怀疑是你英文的理解能力的问题或者是你用全文翻译阅读的这些文字?
你真的读懂了这些文字么?   回复  引用  查看    

#23楼  2007-09-19 21:32 亚历山大同志      

@deerchao
而且你引用文字里没有一句话是说必须有封装,继承,多态才能称之为OO。这样子的观点简直是一个笑话,任何一个懂OO的人都能够明白其中的问题。回头把你引用的段子翻译出来逐字逐句解释一遍自然就明了了。   回复  引用  查看    

#24楼 [楼主] 2007-09-19 21:37 deerchao      

@亚历山大同志
好吧,我承认我看错了一点,作者讲的是Compile time,不是run time.那么把这一条去掉吧.
  回复  引用  查看    

#25楼 [楼主] 2007-09-19 21:38 deerchao      

@亚历山大同志
那我们一起翻译一下第二条和第三条,看谁的理解是正确的?   回复  引用  查看    

#26楼 [楼主] 2007-09-19 21:42 deerchao      

说到翻译我还真有点心得.

I call simple user-defined types, such as Date, concrete types to
我把简单的用户定义类型,如日期,叫作具体类型,以和抽象类与类继承区分,同时
distinguish them from abstract classes (!ì2.5.4) and class hierarchies
强调他们他们与内置类型如int和char的相同点.
(!ì12.3) and also to emphasize their similarity to built-in type
such as int and char. They have also been called value types, and
他们因此被叫作值类型,对它们的使用叫作面向值的编程.
their use value-oriented programming. Their model of use and the
它们的使用模型和隐藏其设计之后的"哲学"与通常所称的面向对象编程相当地不同.
"philosophy" behind their design are quite different from what is often advertised as object-oriented programming

请问您能翻译得更好么?   回复  引用  查看    

#27楼 [楼主] 2007-09-19 21:54 deerchao      

the concepts of a circle and a triangle are related in that they are both shapes; that is,
they have the concept of a shape in common. Thus, we must explicitly define class Circle and class Traiangle to have class Shape in common. Representing a circle and a triangle in a program without involving the notion of a shape would be to lose something essential. This chapter is an exploration of the implications of this simple idea, which is the basis for what is commonly called object-oriented programming.

圆和三角形之间相关性就是它们都是形状.就是说,它们都属于形状这个概念.因此,我们必须显式定义圆和三角形类属于形状类.在程序里使用了圆和三角形而不提到形状失去了一些本质性的概念.这一章就是对这个简单想法的阐述,这正是通常所称的面向对象编程的基本概念.   回复  引用  查看    

#28楼 [楼主] 2007-09-19 21:55 deerchao      

那么您从这里能看到什么呢?
如果您还是觉得用不用"多态"都叫"面向对象"我就不必再讨论下去了.   回复  引用  查看    

#29楼  2007-09-19 22:10 亚历山大同志      

Objects of some user-defined types contain type information.
Such objects can be used conveniently and safely in contexts in which their type cannot be deter-mined at compile time.
Programs using objects of such types are often called object based.

用户定义类型的对象包含了类型的信息。
这样对象能够在在运行时方便和安全的在运行时被分辨。
使用这些类型的对象的程序通常被称之为基于对象的(程序)。(这样子翻译没意见吧)

这些类型是什么类型?自然是前一句的你所谓的能在运行时分辨类型的类型的对象。还有就是Such objects can be used,还是一个很简单的文学问题,can be,not must
be。换句话说是能如何而不是必须如何,完全是自打嘴巴。
再退一步,Object Obj=new User();string Classname=Obj.ToString();算不算多态了,继承了没?你所谓特性是在语言的支持里缺一不可,
应该说是没有继承没有多态没有封装的语言不是面向对象的语言,拿到设计上说事就完全不是这么回事了。

I call simple user-defined types, such as Date, concrete types to distinguish them from abstract classes and class hierarchies and also to emphasize their similarity to built-in type
such as int and char. They have also been called value types, and their use value-oriented programming. Their model of use and the "philosophy" behind their design are quite different from what is often advertised as object-oriented programming

......(前面有描述,比如什么什么样的类型,这样截取是没读懂原文的必然后果)我称为简单用户自定义类型,比如日期,具体类型
以区别于抽象类型和类阶层体系。并强调其和内置类型的相似性。比如 int和char(你截取的那儿啊?读懂了没,这里在讲什么,和你所谓的仅仅使用"具体类型",并不是OOP.有关系么?)
他们也被称之为值类型,他们使用面向数据编程的方式。在他们的设计后的模型和哲学与我们广泛认同的面向对象编程是有很大区别的。

这里是在讲(因为你没截取全,却是部分我臆测了)。主要是关于DTO对象(值类型)是与面向对象的哲学不相符的。完全不不是你所说的仅使用具体类型的那么回事。

Representing a circle and a triangle in a program without involving the notion of a shape
would be to lose something essential. This chapter is an exploration of the implications of this simple idea, which is the basis for what is commonly called object-oriented programming.

在程序里不涉及形状的概念而表示一个圆形和一个三角形会丢失很多必须的信息。(这里看得出来你又没读懂原文,臆断的断句,这两句的上下文根本接不起来)
本章是对什么是俗称的面向对象编程的一个探索(这明显是对一段话的总结,而你却把前面一句多截取出来当作这个结论的前提)

不知道你是真不懂英文还是故意如此,如果是你英文不好我可以理解,但是如果是故意通过截取上下文来达到曲断文义的目的话,我就要怀疑你的RP了。
在对基本的理论都理解不了的情况下这样子讨论问题实在是毫无意义。


  回复  引用  查看    

#30楼  2007-09-19 22:15 hyifeng_ [未注册用户]

@deerchao
@亚历山大同志

OO的经典含义是"封装+继承+多态",少了哪个也不能叫OO.基于对象和OO不是一回事.



讨论前你们要搞清楚是不是在争辩同一个问题,

"少了哪个也不能叫OO"
这句话一种解析是, 语言中少了这种特性, 无法表达这种语义.
另一个解析是, 这段程序没有用到这种特性.

如果是前者的话, 那的确不能叫做用面向对象思想做设计.
因为设计方法是受阉割的.

而后者, 则不一定不是面向对象的程序. 这可能是符合设计的选择.   回复  引用    

#31楼  2007-09-19 22:17 hyifeng_ [未注册用户]

得搞清楚 "能" "不能" "必须" 的关系啊.   回复  引用    

#32楼 [楼主] 2007-09-19 22:22 deerchao      

@亚历山大同志
他们也被称之为值类型,他们使用面向数据编程的方式。在他们的设计后的模型和哲学与我们广泛认同的面向对象编程是有很大区别的。

这里是在讲(因为你没截取全,却是部分我臆测了)。主要是关于DTO对象(值类型)是与面向对象的哲学不相符的。完全不不是你所说的仅使用具体类型的那么回事。
-------------------
怕是您没懂吧?
在C++中,要使用多态,只能通过引用/指针,不能通过值--现在你明白这里的"值"是什么概念了没?就是与引用相对应的那个"值". C++里的值和C#里的可是不一样,那可是想放堆上就放堆上想放栈上就放栈上的,所以这个值只能当作与引用相对立的那个含义来理解.
为什么说这样基于值的编程方式与OOP相当不同?难道基于值不能使用封装和继承吗?显然不是,因于值不能使用多态,这就是作者所说的与OOP的不同之处.   回复  引用  查看    

#33楼 [楼主] 2007-09-19 22:28 deerchao      

@亚历山大同志
他们也被称之为值类型,他们使用面向数据编程的方式。在他们的设计后的模型和哲学与我们广泛认同的面向对象编程是有很大区别的。

这里是在讲(因为你没截取全,却是部分我臆测了)。主要是关于DTO对象(值类型)是与面向对象的哲学不相符的。完全不不是你所说的仅使用具体类型的那么回事。

不知道你是真不懂英文还是故意如此,如果是你英文不好我可以理解,但是如果是故意通过截取上下文来达到曲断文义的目的话,我就要怀疑你的RP了。
在对基本的理论都理解不了的情况下这样子讨论问题实在是毫无意义。
----------------

我花了大约半小时查看原书,而且给出了页码,您可以查看原书看我是不是断章取意了,但是没有实证就这么质疑别人的人品,起到的效果只是让我怀疑您的人品.在你的贴子里你就提到了什么疯子,偏执狂什么的,很好,我退出,不在那里发表意见了,如果您想认真讨论,就请端正您的态度,不然我也不屑于与你继续谈下去了.

回到原题,作者为什么说只提到圆和三角形,不提基类形状缺失了一些本质性的信息?为什么他认为这个问题与OO的基本概念相关?

除了OO的本质就是多态您还能有其它解释吗?
  回复  引用  查看    

#34楼  2007-09-19 22:40 亚历山大同志      

@hyifeng_

我在回复里面说得很清楚了那三个玩意儿是面向语言必须具备的能力而不是面向对象设计所必须使用的语言所具备的特性。
能力和特性完全是两回事,至于继承和多态,在面向对象的语言里(c#,java)不要说C++那个大杂烩。只要继承了都默认的具备了多态的能力,但是是不是要使用却是要依据设计的需要。
这厮非要扯什么三者缺一不可,完全是不可理喻的撒。   回复  引用  查看    

#35楼  2007-09-19 22:44 hyifeng_ [未注册用户]

@deerchao
怕是您没懂吧?
在C++中,要使用多态,只能通过引用/指针,不能通过值--现在你明白这里的"值"是什么概念了没?就是与引用相对应的那个"值". C++里的值和C#里的可是不一样,那可是想放堆上就放堆上想放栈上就放栈上的,所以这个值只能当作与引用相对立的那个含义来理解.
为什么说这样基于值的编程方式与OOP相当不同?难道基于值不能使用封装和继承吗?显然不是,因于值不能使用多态,这就是作者所说的与OOP的不同之处.
---
错漏百出. 对于自己不懂的东西别乱说.


除了OO的本质就是多态您还能有其它解释吗?
----
现在发现你想法的确偏执.   回复  引用    

#36楼 [楼主] 2007-09-19 22:52 deerchao      

这厮非要扯什么三者缺一不可,完全是不可理喻的撒。
------------------------
看来你不是来辩论的,是来骂人的.
C++是大杂烩,C#/Java是"面向对向的语言",不知道玩ruby,python等人怎么看.
你能不能少写几个错别字后再装有学问?--不好意思,我骂人的最高水平也就这样了.

错漏百出. 对于自己不懂的东西别乱说.
现在发现你想法的确偏执.
-------------------
请给出您的论据来,一句"错漏百出"似乎不够分量.

另外,讨论比较激烈时请您批上马甲,免得我以为是一人两声.   回复  引用  查看    

#37楼  2007-09-19 23:03 伍迷      

两位,先消消气。
西方有谚语:
一千人心中有1000个哈姆雷特
我国有俗语:
情人眼里出西施

我觉得每个人对OO的三大特性理解不同是完全正常的。你们的讨论证明你们都已经对OO有了比较深入的理解。

其实用不用多态到是不是OO这不重要,或许学术上本来就有争议,如同鸡和蛋谁先有一样。

我觉得站在更高的高度看问题会更好一些。比如GoF的23个设计模式,其实就有不用多态的,比如单例模式。但它的确是OO。不过如果没有理解多态,可以说对OO的理解就是非常片面和浅薄的,因为多态几乎是绝大多数设计模式成为经典的技术基础。我想deerchao的意思就是想说明它对于OO的重要性。   回复  引用  查看    

#38楼 [楼主] 2007-09-19 23:06 deerchao      

@伍迷
所以我在文章里提到OO时专门在前边加了一个"经典"的定语,指的就是设计模式发行之前主流的OO概念.   回复  引用  查看    

#39楼  2007-09-19 23:11 hyifeng_ [未注册用户]

@deerchao

请给出您的论据来,一句"错漏百出"似乎不够分量.
另外,讨论比较激烈时请您批上马甲,免得我以为是一人两声.
-------
呵呵,
hyifeng是我的这里的帐户, 几年时间没登陆了, 已经忘了密码.
你可以查查帐户应该还在.

我这里指出你那段话几个有问题的地方,

在C++中,要使用多态,只能通过引用/指针,不能通过值--现在你明白这里的"值"是什么概念了没?就是与引用相对应的那个"值". C++里的值和C#里的可是不一样,那可是想放堆上就放堆上想放栈上就放栈上的,所以这个值只能当作与引用相对立的那个含义来理解.
----
你这段话逻辑混乱, 很难逐段点评. 不过我可以告诉你:

在C++中使用多态,不一定要使用指针, 栈变量一样可以.
具体, 你可以考虑一下template method的实现.

而C++中所谓的值,是指具有值语义的对象.这在C++中是一种重要概念.

恩, 还有就是不只是值可以 "想放堆上就放堆上想放栈上就放栈上",
要把对象分配在堆上, 还是栈上完全是由设计者自由支配的.

你说这些话, 没有一句是对的.   回复  引用    

#40楼  2007-09-19 23:20 伍迷      

@deerchao
不过实话说,这句话“判断设计优劣的唯一标准是客户用起来爽不爽.”的确太绝对了。

应该是“判断UI设计优劣的标准是客户用起来爽不爽.”会比较合适一些。毕竟客户只能看到UI,而后台或服务端还有太多的细节是不为客户知的,但程序员却是很清楚,同样是五十个页面查询同一张表,可以写五十遍sql,也可以写一个数据访问类的函数,五十个页面调用。结果对于客户来说是一样的,但如果到要修改当中的某个字段,那就是修改一遍还是修改五十遍的区别,这其实是程序员来判断的设计是否优劣了。   回复  引用  查看    

#41楼  2007-09-19 23:22 亚历山大同志      

@deerchao
所以我在文章里提到OO时专门在前边加了一个"经典"的定语,指的就是设计模式发行之前主流的OO概念.

设计模式是那个年代的事情?那你拿出来讨论的还有什么意义?

要说经典的面向对象也轮不到用C++来说事,要么用JAVA要么用SmartTalk   回复  引用  查看    

#42楼 [楼主] 2007-09-19 23:22 deerchao      

@hyifeng_
我想我们都同意多态的定义大概是这样的吧: 通过基类的接口,调用的是子类的实现.
C++里,如果你传递一个基类的指针,调用它的虚函数,没问题,调用到的是子类的实现;
但你传递一个把一个子类实例/值/变量作为基类的传递,很对不起你传递过去的只是一个基类,这时发生了"对象切割",你对这个基类调用虚函数,是不可能调用到子类的实现的.
Template Method我当然知道,但是你在C++里不传递指针来实现一个试试?不可能的事.

而C++中所谓的值,是指具有值语义的对象.这在C++中是一种重要概念.
-----------------
当然,这个值语义的对立面是什么?正是引用语义.
你在说明这个"值"的概念之后,又提了一个"不只值"的"对象",似乎没有这种概念吧?
对象就是对象,你可以持有它的值,也可以持有它的引用,--值之外的对象,这种说法没有任何意义.
  回复  引用  查看    

#43楼  2007-09-19 23:22 hyifeng_ [未注册用户]

其实我没有兴趣跟你纠缠是否必须多态的问题. 所以就到此为止了.

我不是某人马甲又一力证.   回复  引用    

#44楼 [楼主] 2007-09-19 23:28 deerchao      

@亚历山大同志
你在这里发表第一个回复之后我就说明了我的定义是什么.并且一再拿出"基于对象"与"面向对象"对比,你偏视而不见我有什么办法.

概念不在于早晚,就是现在,认同OO等于多态的人还是大有人在.我没有拿C++来说什么事,只是我读书比较少,没看过多少能吓倒人的巨著,不得以拿了几年前看过的TCPL里的几句来撑撑场面.我只是说明,至少C++作者心里的OO也是与多态关系相当密切的.

另外,"经典"为什么要拿Java来说?你自己都说过了Java推崇接口让很多经典的OO论者不爽了?   回复  引用  查看    

#45楼 [楼主] 2007-09-19 23:30 deerchao      

@hyifeng_
现在我们的问题不在于多态不多态了,而是检验您对C++的了解是不是比我更深,说我"错漏百出"是不是有理有据.
人要为说过的话负责,不然人人都可以信口胡言的.   回复  引用  查看    

#46楼 [楼主] 2007-09-19 23:34 deerchao      

@伍迷
其实前面还有一条:使用你的程序的人就是你的客户.别拿同事不当客户,也别拿自己不当客户.
粗制滥造的代码不可能让用它的人舒服的(不管这个人是自己还是客户).   回复  引用  查看    

#47楼  2007-09-19 23:37 hyifeng_ [未注册用户]

谁让你对象切割了?

struct CBase {
void getX() { ... getXImpl() ...}
virtual void getXImpl() = 0;
...
};

class CMyExt : public CBase { ... };

CMyExt myObj; // 栈变量
myObj.getX(); // 不用指针

你说这里多态了没有?

  回复  引用    

#48楼  2007-09-19 23:40 hyifeng_ [未注册用户]

我理据都列给你了, 你不承认我也没撤.   回复  引用    

#49楼  2007-09-19 23:40 伍迷      

@deerchao
Sorry,非常抱歉。我断章取义了。   回复  引用  查看    

#50楼 [楼主] 2007-09-19 23:41 deerchao      

请问你那是通过基类的接口调用的吗?

通过基类接口应该是这样:
CBase myObj= CMyExt();
myObj.GetX();   回复  引用  查看    

#51楼 [楼主] 2007-09-19 23:45 deerchao      

@伍迷
嗯,我觉得广义一点理解客户其实可以简化设计决策时的考虑,至少像我这种不懂OO的人不用考虑那么多.
反正我就想着客户怎么用着爽就怎么做就行了.   回复  引用  查看    

#52楼  2007-09-20 00:00 hyifeng_ [未注册用户]

不管怎么样, 我那段代码足够证明你说只有通过指针引用才能应用多态 是一个错误了.


至于你认为必须是你说的这样:
CBase myObj= CMyExt();
myObj.GetX();


那只能说你抽象的程度还不够,
在我眼中,
CMyExt myObj; 他就是一个CBase, myObj.getX(); 就是调用 CBase 的接口方法,
而你, 却必须签名为CBase 才觉得他是一个CBase.

这在泛型程序中应用的多了,
template <typename T> // C++0x语法更好: template <CBase T>
void DoSomething()
{
T obj;
obj.getX(); //CBase 接口
}

  回复  引用    

#53楼 [楼主] 2007-09-20 00:09 deerchao      

@hyifeng_
前边我提过"通过基类的接口,调用的是子类的实现.",你没有反对吧?

多态的目的就是不关心具体类型,你使用具体类型来调用一个方法,这样就算称它是"多态"又有什么意义?

泛型与多态的关系就更远了,一个是静态的,一个是动态的,与我们的讨论根本不相关.当然你可以说这更"抽象",但问题是我们讨论的是前面已经明确定义了的多态.   回复  引用  查看    

#54楼  2007-09-20 00:11 hyifeng_ [未注册用户]

当然,这个值语义的对立面是什么?正是引用语义.
你在说明这个"值"的概念之后,又提了一个"不只值"的"对象",似乎没有这种概念吧?
对象就是对象,你可以持有它的值,也可以持有它的引用,--值之外的对象,这种说法没有任何意义.

--------

值语义不等同与栈变量, 你要好好补补概念了.   回复  引用    

#55楼 [楼主] 2007-09-20 00:14 deerchao      

另外,多态通常也被称为"动态绑定",你的那个例子,十有八九都是静态绑定--编译器直接给你优化了,所以拿来较真也许还真能吓吓人,但是实际意义又有多少呢?   回复  引用  查看    

#56楼 [楼主] 2007-09-20 00:15 deerchao      

@hyifeng_
我只是提一下C#里的值类型自动分配在栈上,什么时候说过C++里的值语义等同于栈变量了?   回复  引用  查看    

#57楼  2007-09-20 00:23 hyifeng_ [未注册用户]

这样就算称它是"多态"又有什么意义?
----------
意义在于, 我*没有*偏执地认为 "只能使用栈对象".
所以, 我没有否定使用基类接口指针的意义.

但我也不认为栈对象的多态行为毫无意义
我举的例子,在泛型方法中我就忽略了对象的具体类型. 并利用了他们的基类接口.
并且, 那的确是一个栈变量+多态. 更重要的是, 这段代码的确*有用*.

我发现我已经够长气了, 我过去一年发的贴也不过就这么多.   回复  引用    

#58楼 [楼主] 2007-09-20 00:26 deerchao      

写出具体类型名称的"多态"我还是认为没有作用,直接被编译器静态解决.

泛型的那个例子你怎么调用,这样?

DoSomething<CMyExt>();

还是写出了具体类的名称.   回复  引用  查看    

#59楼  2007-09-20 00:29 hyifeng_ [未注册用户]


DoSomething(new CMyExt);
你还不是一样写出了具体名称了?


算了, 你们还是继续是不是Must be的问题吧.   回复  引用    

#60楼 [楼主] 2007-09-20 00:32 deerchao      

我可以用DoSomething(CBase *).
本来讨论的就是只有使用指针才能使用多态,好吧我加个定语,"比较有意义"地使用多态.   回复  引用  查看    

#61楼  2007-09-20 09:22 双鱼座      

1,没有银弹.
此乃软件工程述语。与软件设计何干?

2,客户需求是一切设计的根本.
也太泛客户化了,通常有人改善设计的目的只是把一些可积累的东西积累下来以供后续的项目和产品使用。

3,使用你的程序的人就是你的客户.别拿同事不当客户,也别拿自己不当客户.
同上。如果什么人都是客户,那分客户这个概念还有意义么?

4,判断设计优劣的唯一标准是客户用起来爽不爽.
可能界面上是这样。系统内部却不一定。

5,抽象得好与不好全看你的需求会怎么变化.
就这句话有点靠谱,不过还是有问题。可以写成:“是否需要进行抽象以及抽象到什么程度全看你的需求会怎么变化”。

6,看不惯Book.Save()只说明你没有理解软件是什么.
我也看不惯,但并不能证明我是否理解了“软件是什么”。如果写成Book.Save(Context)我就看得惯了。从逻辑上,Book.Save()似乎缺少某些条件,可能在Book这个对象中隐藏了某些公共的东西,所以有可能存在边界问题。

其实年轻人的偏激是可以理解的,真正的厉害家伙都存在某种偏执。所以我这里不是想纠正你,而是向你传达另外一种你没有关注的一种可能性。   回复  引用  查看    

#62楼  2007-09-20 09:24 亚历山大同志      

@deerchao
说着说这就扯远了,
回到原题,首先我承认我的C++功力非常有限,在大学里学过我就直奔Java去了。
而且你也承认,你的大部分面向对象的概念是来自C++的,而就大部分使用面向对象语言(C++不算,因为C++是基于对象的语言,有对象的概念,但是很多面向对象的特性需要依靠开发人员本身的素质-----这点来自你的原话)。所以大部分的争论基本毫无意义,你提出的三点必须存在的特性在C#,java中已经事实存在,我也举了很简单的C#的例子 Object a=new User(); a.ToString();这么就已经是在使用多态的特性了。
但是你不依不饶的强调在一个语言因为自身的特性而造成的必然约束,然后推而广之,放大到其他语言就是绝对不正确的。所以我要说你是不正确的,其实就和用C来对面向对象说事一样,其实C语言一样可以面向对象,一样的可以实现继承,封装,多态,为什么没人说C是面向对象的语言?
还有你的观点老是在左右摇摆,你既要维护“经典面向对象”的体面,但是确又拿出错误的武器C++。经典面向对象理论最纯粹的体现是SmartTalk,不过很少人用。而事实上面向对象的标准基本上是Java、C#这类真正面向对象的语言。
你又摆出了Python,Ruby,这类语言是支持动态类型的语言,马上C#就已经要加入这类特性了。
面向对象实在不断进步当中的,如果你抱着"经典"不放,3年前的老观点在IT时代已经能够判断一个人是从石器时代回来的了。   回复  引用  查看    

#63楼  2007-09-20 09:27 亚历山大同志      

@双鱼座
Book.Save(Context) 确实 比Book.Save()要好,起码解决了Book.Save()很多上下文不明确的问题,比如事务。不过很多时候Book.Save()只是一个泛指   回复  引用  查看    

#64楼  2007-09-20 10:04 xiao_p      

你们几个真强。。。
咬文嚼字 其实没有什么意义,
大道无言,不是说出来就可以了,关键是在实际的开发中能把你的思想转化为动力。

  回复  引用  查看    

#65楼 [楼主] 2007-09-20 11:04 deerchao      

@双鱼座
只说明你没的看懂我的意思.

此乃软件工程述语。与软件设计何干?
------------------------------
没有银弹在这里指的当然是软件设计必须从实际需求出发,没有哪种设计能在所有项目里适用.

也太泛客户化了,通常有人改善设计的目的只是把一些可积累的东西积累下来以供后续的项目和产品使用。
---------------------------
请不要忘了后边的"自己"和"同事"也是客户的说法,"把一些可积累的东西积累下来以供后续的项目和产品使用",在这个说法的前提下,这个算不算满足客户的需求?

同上。如果什么人都是客户,那分客户这个概念还有意义么?
------------------------
当然有意义,像我这样不学无术的人,被别人的OO啊,模式啊,ORM啊什么的吓倒了不敢设计的时候,只要想着我唯一的目的就是满足客户需求,就敢于动手了.

判断设计优劣的唯一标准是客户用起来爽不爽.
-----------------------
请参见上一条. 这几条是相互关联的一个整体,要批判请一起批判,别个个击破.

就这句话有点靠谱,不过还是有问题。可以写成:“是否需要进行抽象以及抽象到什么程度全看你的需求会怎么变化”。
-----------------------
我一个初学者用点通俗易懂的词想来也不是什么罪过."好不好"这个说法比较平易近人,不会吓跑别的初学者,而且字也少几个,打起来比较方便.


我也看不惯,但并不能证明我是否理解了“软件是什么”。如果写成Book.Save(Context)我就看得惯了。从逻辑上,Book.Save()似乎缺少某些条件,可能在Book这个对象中隐藏了某些公共的东西,所以有可能存在边界问题。
----------------------
我这句话本来的含意是"软件设计, 归根结底不应该是对现实世界抽象, 而是对"就某个问题, 使用计算机去更好的解决"这一过程的抽象, "(来自怪怪的文章),给有"书怎么办保存自己"这样想法的人看的.
虽然跑题,但是不看需求你就能从Book.Save()上看出逻辑问题来?
我总结这几条原则的目的就是要说明需求是一切设计的根本,不谈需求,空谈设计是没有任何意义的.

其实年轻人的偏激是可以理解的,真正的厉害家伙都存在某种偏执。所以我这里不是想纠正你,而是向你传达另外一种你没有关注的一种可能性。
--------------------
你首先要明白我错在哪里才有可能纠正我,但是就我看到的是你没有明白我表达的意思,而且在断章取意.   回复  引用  查看    

#66楼 [楼主] 2007-09-20 11:22 deerchao      

@亚历山大同志
首先我承认我学习OO是从C++开始的.
其次我并不想提到C++,是你要求我在"有分量"的书里找到OOP与多态等的关系的话,我没有文化,没读过多少书,觉得读过的可能算是"有分量"的也就是C++之父的书了吧.所以我从里面摘了两段,摘这两段讨论的不是如何使用C++进行OOP,而是说明C++之父认为OOP和多态的密切关系.
"一个语言因为自身的特性而造成的必然约束",我的重点没在这里,我拿C++书里的话来只想说明C++之父心里的OOP是怎么回事.当然后来有人中途搅合,说C++里可以如何如何,最后说明那只是一个没有意义的Trick.
C++不是武器,我也并不有用C++当武器原意思.这里与C++的唯一关系就是C++之父的观点是我的论据.
我的观点没有任何摇摆,那就是经典的OO就是指多态.

与时俱进不是把某个词当一个筐,什么玩意儿都往里装.概念必须有其严格定义,不然谁知道你说的是什么?如果你真的与时俱进,并且听说过"敏捷","TDD"的话,我相信你能从我总结的几点里品出它们的味道来.


另外,我摆出ruby, python等是针对你认为C++不算OO语言,Java/C#才算的论点.
还有一点,与题无关,但是我还是想说一下,C#从出生到现在都是一个静态强类型语言,它根本动不起来(当然你首先要明白什么是C#的能力,什么是CLR的能力),"马上C#就已经要加入这类特性了"这个观点很是不值批驳.
  回复  引用  查看    

#67楼 [楼主] 2007-09-20 11:28 deerchao      

@xiao_p
可是每天见到别人拿些大字眼来唬人,总是烦.说一个Buzzword前至少要明白它是什么含义吧.一个只用到了封装的示例标题居然也敢叫"必须使用面向对象才能解决"什么什么的,我直接就要晕了.   回复  引用  查看    

#68楼  2007-09-20 12:00 双鱼座      

@deerchao
惭愧啊。原来你的意思是初学者都能明白的,但是我居然没有明白。

那我就以初学者的态度来回答你。没有人说要离开需求讨论设计,也没有人说客户不重要,你何苦这么极端。不同的客户要采用不同的设计,这里没有任何象你所说的这么简单而没有任何实际意义的原则,而是一组复杂精妙而意义深远的原则。当然,其中就包括OO。

顺便说一下,无论你是什么需求,Book.Save()都可以被怀疑存在逻辑问题的。无非是你要告诉我,Book中已经隐含了上下文嘛。任何事情都有一定规律,所谓规律就是能应付不同的场景(正是你说的需求)。Book.Save(Context)其实是Context.Save(Book)的衍变。你能举出一种需求可以脱离这样的背景么?   回复  引用  查看    

#69楼  2007-09-20 12:04 kingren [未注册用户]

博客园的气氛真好。
争论中提高。
学了不少东西。   回复  引用    

#70楼 [楼主] 2007-09-20 12:13 deerchao      

@双鱼座
我没有说过你连初学者都不如,我只是说我总结这几条原则是为了让像我这样的初学者不被buzzword吓倒,不敢动手.
--如果你认为这样是"简单而没有任何实际意义",那只能说你是高人,不懂像我我这样的初学者被那些理论啊原则啊框架啊思想啊什么的弄得无所适从,你是摘叶飞花均可伤人,根本就不需要原则了.
另外,OO是设计的原则我还是头一次听说,原来那么多C程序员,一辈子都在做不符合软件设计原则的事情.就我看OO只是一种手段,有效时就用,无效时就扔,哪里上升到"原则"这一高度了?
我不知道你用过对象数据库Db4O没有?里面保存数据的方法就是Object.Set(),就是这么简单,你认为这里是有逻辑问题的?另外有很多ORM框架,保存对象用的也是类似的方法,比如ActiveRecord里,用的就是Object.Save().你也认为他们的实现都是错误的,是有逻辑问题的?以我看,Context不能由Book自己获取--这样的观点才是有逻辑问题?
  回复  引用  查看    

#71楼  2007-09-20 12:56 徐少侠      

--引用--------------------------------------------------
deerchao: @亚历山大同志
在The C++ Programming Language 3rd (Bjarne Stroustrup, 1997)里:
--------------------------------------------------------

有相当多的反对意见
在The C++ Programming Language 3rd (Bjarne Stroustrup, 1997)里:
第9页:
使用不能在运行时分辨类型(意思自然是没使用多态,我想这点你不反对吧)的对象
理解不一致
不能再运行时分辨类型不是说没有使用多态
cannot be deter-mined at compile time
注意这里的Compile正确的翻译是编译
很明显即使是面向对象的多态也是说无法在编译时分辨对象的
这里估计你肯定错了

正确的含义是,在编译时无法确定类型
举例来说
Javascript不是面向对象的
虽然他里面的变量在运行时实质都是有类型的,但是在非运行时无法知道是什么类型
同理很多脚本语言都是这样的
因此由于在语言中支持对象的使用,但又有类似这样的缺陷,这些脚本语言被称为给予对象的语言

第252页:
They have also been called value types, and their use value-oriented programming.
这段文章的意思,其实是说如果仅仅封装了值类型数据,不能作为面向对象的例子。
因为面向对象的基本思想不仅仅是封装和对象有关的数据,而是进一步将对象自身的行为放到内部并有选择的公开
所以,这里你也有很大的问题