程序员的一天的郁闷之四(类的继承跟类的合成)
大家好,我又来郁闷了!我所工作的地方,的项目组,在编写类的时候,其本上都是用合成的方法!打个比方,有个车的大类,然后分成公共汽车,小汽车,货车,货车又分为,大货车跟小货车!
我们单位的头的作法是这样子的,它叫上五个人分变写,公共汽车的类,小汽车的类,大货车的类,小货车的类(在程序文档中的功能都实现了)然后用合成的方法实现了车这个模块的所有功能!当然,当中的很多方法都没重用!
我曾向他提仪用继承的方法,他说继承太慢了,因为要编写下一层的类,要上一层写完才能写,上一层写完后,上一层的人又没事做了! 我觉得它说的也有道理,
请问你们工作的地方,都昨么组织写类的啊!
注意,散分,有答有分!
问题点数:50、回复次数:25Top
1 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-12-20 19:37:37 得分 0
不会先约定接口啊……Top
2 楼zhaoyixiao()回复于 2005-12-20 20:02:09 得分 0
接口?好像我们公司没用这玩意,他说,接口是不科学的!Top
3 楼henryfan1(http://henryfan.cnblogs.com)回复于 2005-12-20 20:17:33 得分 0
他说,接口是不科学的!
有人说这样的话,真是没什么好说的了!
我们项目开发前就定义好模板类,表现层,业务层都有。
开发人员编写的类必从已有的模板类派生出来,不得违反这个规则。
如果你想说服你的头,你必须有相应的应用案例(自己写的);如果单凭你的见解那是很难得到认同的,有对比才有差别。Top
4 楼xinggg(风之渡)回复于 2005-12-20 20:23:48 得分 0
有些不一定是继承好啊,如果没太大的联系,用合成更好吧,接口,个人认为是好东西Top
5 楼xinggg(风之渡)回复于 2005-12-20 20:27:30 得分 0
我感觉楼主描述的似乎是各个子模块分别开发,然后再挂到总模块上,这种可能用合成更好吧?Top
6 楼zhaoyixiao()回复于 2005-12-20 21:04:43 得分 0
我所说的合成,有包含互相调用的方式!比如三个类A(砍材,跳水,洗碗,洗手)B(点火,煮饭,煮菜,洗手)C(吃饭,洗手)
A,B,C三个都有一共同的方法,洗手,所以这个类还可以细分出一个D类,洗手
我的项目经理的做法,就是把类分成很小很小的类,每个类,只实现一个到二个的方法
现在要吃饭,吃饭要煮饭,所以创建在C中创建A的实例,实现A的三个方法,然后在调用B的实便,实现B的三个方法,最后,用自个的方法,吃饭!我们的公司,全部是这样子做的,然后一个程序员,做一个模块,项目经理的做法就是细化类!然后用合成!
我曾提议过用接口,他说接口跟继承都是拉圾,只要类细化到最小,就不存在代码改变后,都改的问题!因为它说,我调用洗手的函数名,跟返回的对像类型不改就行了!接口不也是规定不能乱改接口名吗?我们不改函数名,跟方法就行!
你们的公司,是昨么做的啊!我有时也觉得接口好像是多余的,接口不能实例化
Top
7 楼xczgb(TJJTDS)回复于 2005-12-20 21:39:27 得分 0
接口是垃圾?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Top
8 楼zhaoyixiao()回复于 2005-12-20 21:54:27 得分 0
严重BS我的项目经理!Top
9 楼SHOWMSDN()回复于 2005-12-20 22:03:21 得分 0
我们虽然没有完全定义好每个层该用到的东西。但基本上也做到了,已有数据访问层的情况下,详细定义业务逻辑层,定义完毕以后熟悉后台的开始完善类,熟悉前台的写前台。Top
10 楼zhaoyixiao()回复于 2005-12-20 22:07:55 得分 0
他说,接口方便了别人,吃亏了自个!
public interface IAge
{
///接口属性
int Age{ get;}///功能返回年龄
string Name{ get;}///功能返回姓名
}
只要有了这个 共用的接口,在.NET平台上,用C#,VB.NET, J# 都能实现上面的功能!何必呢!只要用一种语言开发就行了!Top
11 楼kjq_vb(跟着MS走)回复于 2005-12-20 22:33:14 得分 0
第一次听人说继承是垃圾Top
12 楼misvcom(零下一度)回复于 2005-12-20 22:59:01 得分 0
我们那里是先做好了一个程序核心,然后各个程序员负责不同的插件,到最后都挂在一起就行了Top
13 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-12-21 00:43:50 得分 50
真不知道你们那个家伙怎么做到项目经理的。
你把类细分到一两个函数的级别,那就等于是C语言了。因为C只有函数而没有类。
而把代码Copy & Pastal则退化到C语言以前的地方去了。
代码复用的最大的好处不是我们少敲几个字,而是最大限度的保障代码质量,就算发现错误,也只需要改动一处即可。
再说,编程之前不先约定接口,你们那个项目经理真是吃X的。别说我说粗话,他就真是吃X的。
作为系统架构师,或者说项目经理,要统观全局,懂得怎么去整合大家的代码。给每一个程序员下达的任务都应该明确的标注所有的接口类型(这里说的接口并不是指Interface)。
例如说现在要做一个做饭吃饭的项目。
那么架构师应该很清楚这个需要砍柴。
那么指派一个程序员编写一个樵夫类,樵夫类对系统的接口应该是交付柴火,而他自己的实现可能还有磨刀什么的。
架构师就要先定好柴这个类。
然后樵夫类和煮饭者类最后才能契合在一起。如果樵夫类给出的是湿柴,煮饭要的是干柴。那饭就没法煮了。
然后,进一步分析。
樵夫和煮饭者两者有共同的操作,例如洗手。
这是一个算法,如果确认这两者的算法是完全一样的。那么就应该把这个算法抽出来,做成帮助类,提供给所有的人。
其实先做什么后做什么并没有大的关系。
例如只要柴可以定义好,那么樵夫和煮饭者两个类就可以同时开工。
而遇到中间的小算法问题,则可以让写樵夫的或者写煮饭的谁先遇到这个问题,谁先遇到就谁先写,再作为公共函数独立出来。
一直都没有说到继承的问题。
但是这个也完全不是你们项目经理的那个说法。
微软的ADO.NET这样庞大的东西,都不可能是一个人写的。很可能是SqlClient命名空间由一个团队开发,Oracal命名空间由另一个团队开发。
但是这两个命名空间中的东西,用到了很多相同的基类,例如System.Data.Common.DbDataAdapter。
Top
14 楼zhaoyixiao()回复于 2005-12-21 00:47:50 得分 0
我们项目经理,强调的是组件,就是软件的合成!看来他说的是有些道理噢!网上搜了很多的文章,也特别强调组件,用给合的方式,而不是继承的方式!Top
15 楼zhaoyixiao()回复于 2005-12-21 01:05:28 得分 0
顶楼的,你说的大部分意思,也是组合呢,只不过,我们的项目经理,没用接口的方式,连接组件!樵夫跟煮饭是二个不同的类,它们的共同方法是洗手,你也提另做一个类!那就三个类,樵夫类,煮饭类,洗手类!这三个没联系,也就是“黑箱“ 我们的项目经理主要意思,就是细化类,然后组合,不过它没用到接口!举个例子!
public class A //包装二个属性
{
public int a;
public int b;
}
public class B // 包装一个方法
{
public int Add(int a, int b)
{
return a + b ;
}
}
public class C // 合成这二个类
{
A a = new A();
B b = new B();
//输出一个结果
}
如果是继承
public class B : A
{
public int Add(int a, int b)
{
return a + b ;
}
}
public class C
{
B b = new B()
//输出一个结果
}
也就是说,二个功能是一样的!一个用继承一个用合成!
我们的项目级理,指挥我们用合成!
接口昨么写来者,有人会吗?Top
16 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-12-21 07:55:07 得分 0
组件就不可能粒度太小,粒度太小就不是组件。
说白了就是你们项目经理根本就不懂OOD罢了。
并且!你上面举出的所有例子都是面向过程的结构化编程,没有一点儿面向对象的影子。程序不仅仅是按照流程一个一个功能的调用,如果都是这样编程,OOD也无从谈起。
继承所带来的代码复用在.NET Framework中随处可见,你为什么不研究一下.NET Framework呢?
顶楼的,你说的大部分意思,也是组合呢,只不过,我们的项目经理,没用接口的方式,连接组件!樵夫跟煮饭是二个不同的类,它们的共同方法是洗手,你也提另做一个类!那就三个类,樵夫类,煮饭类,洗手类!这三个没联系,也就是“黑箱“ 我们的项目经理主要意思,就是细化类,然后组合,不过它没用到接口!举个例子!
这样做是对的,但是我不相信一个项目里面全都是这样的东西。
如果你要煮饭,又要煮汤,又要煮药,那么继承的优势就出现了。
public abstract class 煮东西
{
private 柴火 _干柴;
private 锅子 _铁锅;
public void 获得柴火( 柴火 干柴 )
{
_干柴 = 干柴;
}
public void 获得锅子( 锅子 铁锅 )
{
_铁锅 = 铁锅;
}
public abstract 汤 煮东西( 能煮的东西 );
protected void 生火()
{
//...
}
protected void 加水()
{
//...
}
protected void 煮( TimeSpan timeSpan )
{
//...
}
public event EventHandler 煮好了;
}
模版方法模式。Top
17 楼flybeyondhj(楚之狐)回复于 2005-12-21 08:58:07 得分 0
Ivony(*) ( )不愧为星级大将,让我学习了不少,谢谢!Top
18 楼wuyazhe(wyz&xyl)回复于 2005-12-21 09:16:43 得分 0
我认为,继承的时候。适当的使用委托。简直绝了。比如基类一个函数,需要执行n个子类的操作,操作一开始不确定有几个,操作可能随时变更,使用+=,-=来添加到委托里,基类调用一句委托,就按要求执行所有的操作。(不知道我说清楚没有,昨天看刚上任的c#版主blog学的)。
public delegate void myShowMessage(string str);
private void button1_Click(object sender, EventArgs e)
{
myShowMessage delObj = new myShowMessage(myShow);
delObj += new myShowMessage(myShow2);
delObj("abcdefg");
Random rnd = new Random(DateTime.Now.Millisecond);
MessageBox.Show(rnd.Next().ToString());
}
private void myShow(string str)
{
MessageBox.Show(str);
}
private void myShow2(string str)
{
MessageBox.Show(str + "\r\n" + str);
}
不知道是不是说跑体了。总之,我是说,继承很好,接口很好,同时配合上委托的灵活使用,更是很好。说简单,用了c#,还真对得起咱这个键盘。嘿嘿
Top
19 楼zhaoyixiao()回复于 2005-12-21 18:28:45 得分 0
继承 ( inheritance ),是类 D 的对象可以使用仅对类 C 的对象有效的方法或者属性的特性,它使得这些方法和属性就好像是由类 D 定义的。这时, C 是 D 的父类, D 是 C 的子类。在继承结构中,父类的内部细节对于子类是可见的。所以我们通常也可以说通过继承的代码复用是一种“白盒式代码复用”。 组合 ( composition ),是通过对现有的对象进行拼装(组合)产生新的、更复杂的功能。因为在对象之间,各自的内部细节是不可见的,所以我们也说这种方式的代码复用是“黑盒式代码复用”。 继承和组合各有各自的优缺点。比如说,对于继承,我们可以在编译期静态地定义其层次结构;因为 OOP 语言直接支持继承特性,使得在技术上来说,继承直白明了易于使用;而且,我们也可以很容易地修改通过继承所复用的实现代码。但是,我们不能够在运行期间改变通过继承得到的实现代码;而且更加不好的是,父类常常会定义一部分子类的表现特征,使得父类和子类之间的实现代码产生相互依赖,也就是所谓的“ 继承破坏封装性 ”( inheritance breaks encapsulation )的说法。代码依赖将会导致很多问题,例如通过继承而来的实现代码可能会不适用于新的问题域,从而使得我们需要去重写父类或者替换掉某些实现代码。同时,代码之间的依赖关系,限制了程序的灵活性和可复用性。 对比而言,对象的组合是在运行期间通过对象之间的引用动态定义的。组合要求对象互相尊重( respect )对方的接口。不过这样做下来,因为对象之间只能唯一的通过接口相互作用,对象的封装性也就得到了良好地维护。同时,在运行期间,任何对象都能够被替换为其他相同类型的对象。更好之处在于,因为对象的实现代码只和其接口有关系,所以由潜在的代码依赖所带来的问题出现的机会就大大减少了。对于整个系统的设计而言,使用对象组合将保证各个类能够被良好的封装起来,并且保证这些类能够只负责解决唯一的问题。这就使得类的层次结构能保持比较小的规模而不至于变成难以控制的庞然大物。在基于对象组合进行设计的系统中,会有更多的对象、更少的类,系统的行为将由对象之间的交互关系来决定。 在理想的情况下,我们不需要创建新的组件来完成代码复用,而只需要通过对象组合的方法来拼装已存在的组件以获取新的功能。但这种情况很少会出现,因为在实际情况中,现有的组件总是显得不够,而通过继承来复用代码往往要比通过组合对象要容易得多。所以继承和组合两种方法并存于我们的实际软件开发过程之中。 举个例子来说,我们通过 Array 来实现一个 Stack 类。有两种方法,第一种是把 Stack 作为 Array 的一个子类,也就是通过类继承的方式来实现这个 Stack 类。 class Stack extends Array { // etc… } 第二个方法是将一个 Array 类型的实例作为 Stack 类的一个属性,也就是通过对象组合来实现 Stack 类。 class Stack extends Object { private Array anArray; // etc… } 在这个例子中,使用组合来实现 Stack 类的效果会更好一些。因为这样 Stack 的实例就不用再继承多余的 Collection 类的方法和属性了。 作者Blog: http://blog.csdn.net/holy_phoenix/ 相关文章 面向对象编程中的继承和组合的简单比较 工作 42th week, 2004 UML和模式应用读书笔记/要点概记Top
20 楼zhaoyixiao()回复于 2005-12-21 19:25:23 得分 0
优先使用对象组合,而不是类继承
我不能够同意这一点,不应该对继承存在偏见,尤其是接口继承,一个问题的解决,如果存在组合和继承两种方案,多去思考一下各自的优缺点,而不要先入为主的自以为是地选择对象组合。
如果非要我这两个方法中选择优先级的话,我的选择是相反的,优先使用继承,而不是对象组合。但继承不能够很好地表达事物的本质的时候,才应该使用对象组合。我们知道,基于继承的代码和框架会比对象组合来的简单和优雅。
看事物的本质,往往是在事务的静态方向,而静态方向适用于继承来解决,而动态的行为,不一定说就一定要用对象组合。
只所以大家对继承反感,我相信很大一个原因是大家对继承滥用了,但是继承本身仍是优先选择的方法。
我并不是对对象组合存在偏见,我只是认为使用任何方法都是有成本的,对于一个问题的解决,我会选择一个成本最低的方式。Top
21 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2005-12-21 19:58:50 得分 0
继承最大的好处是接口统一,适应于将来未知的情况。
在.NET Framework中,继承带来的好处是显而易见的,例如方便我们进行数据绑定的ToString方法即是从Object继承而来,而析构函数(Finallize)也是依赖于继承来保证调用到子类的。
继承不是隐藏,而是抽象,当对象和对象要发生关系时,就出现了方法和接口的概念,例如用锅子煮饭。如果我们将接口僵化成 锅子.煮饭( 米, 水 ),那么我们在要煮汤的时候,就不得不写一大堆似曾相识的代码,即使这些代码仍然可以再次细化而从锅子中抽取出去。但是将这些东西抽取出去会破坏对象的封装,产生另人难以理解的生火类。增加调用层次,增加了代码的复杂性,增加耦合度。Top
22 楼aimcy(Debian)回复于 2005-12-21 20:52:46 得分 0
学习Top
23 楼aicode(加勒比海盗(I Love C++))回复于 2005-12-21 21:41:18 得分 0
模板方法加大了类之间的耦合,不如用STRATEGY模式 ^_^
另说一句.楼主你们项目经理对OO理解绝对有问题.竟然说接口不科学.OO强调的就是依赖于抽像编程.模块之间的调用也应该依赖于接口.Top
24 楼aicode(加勒比海盗(I Love C++))回复于 2005-12-21 21:42:38 得分 0
再顶一下. .net区终于有好帖子了.Top
25 楼zhaoyixiao()回复于 2005-12-22 20:10:45 得分 0
我狂顶Top




