院刊的技术版的编辑domi和我是好朋友,前几天我说想发一篇文章,他爽快的答应了.随后才发现想要写的东西很多.最后费了一天的时间.终于决定写一些关于面向对象的东西.于是就有了下面的thiking in OO.虽然写的的不怎么样,但就像domi所说的:精神可嘉!
到现在为止,我们的学习语言之路是这样被安排的C -> C++ -> Java -> C#,其中的三种是面向对象的,可是每次当老师站在讲台上一遍又一遍地念着OO(Oriented-Object面向对象)大魔咒:"继承,多态,封装"时,我们有没有思考这样的问题:我们真正在Thinking in OO吗?
当我看见眼前无数的if else语句时;泛滥的继承时;耦合得像胶水一样的设计时;我对"量变导致质变"的理论不禁产生了怀疑.
是什么让我们与OO若近若离?也许是我们对面向对像的狭隘的目光.
1.什么是对象?
什么是对象?"拥有方法的数据"也许你都可以不经过思考就会答出来,而且这样的回答也足够换回老师的赞同(试卷上一个完美的大对号).可是,一切也同时结束了.我们还是在面向过程的泥潭中建造面向对象的乌托邦!一个好的设计原则是:对象应该对自己负责,并且这种责任应该清楚的被定义出来.可能我们的对面向对象局限性这和我们对待事物的视角有关系,所以我想用OO大师
Martin Fowler的观点描述一下软件开发过程中的三个不同的视角(perspective).
----- 概念(conceptual) 这个视角"展现了问题领域中的概念……一个概念模型可以在对实现软件有很少或毫无注意的情况下画出……"
----- 规格(specification) "现在我们看看软件,但我们只是软件的接口,而不是实现""
----- 实现(implementation) 现在,我们置身于代码本身."这可能是常用的视角,但在许多方面,规格视角经常是更好的视角"
现在我们想一想是不是我们平时在思考问题时只是停留在实现的视角呢?如果用以上的视角来观察对象:
----- 概念(conceptual) 一个对象是一系列责任
----- 规格(specification) 一个对象是一系列可以被其他对象或该对象自己调用的方法
----- 实现(implementation) 一个对象是一系列代码和数据
2.继承真的能解决问题吗?
"通过为每个东西创建特定的情况"来解决问题是多么的容易!这是每个向我们演示关于继承的例子的老师都会发出的赞叹.这样的解决方案确实很直接.它让我们在不改变现有的系统的情况下添加新的方法,可是当我们再一次思考时,也许会发现在轻松的解决问题的同时,我们是以高度的冗余,较低的内聚,以及"类爆炸"为代价.从而导致我们的代码毫无可维护性和复用性--而提高可维护性和复用性正是软件设计的最重要的目标中的一个啊!对继承的过度依赖让我们偏离了OO.
3.封装的只是数据吗?
当我们谈到封装概念,它经常被描述成为"数据隐藏".是的一般情况下,对象不会把其内部的数据暴露给外面的世界.于是我们又开始了面向对象的设计,因为我们觉得public
private, protected的用法是如此简单.但这就已经足够了吗?封装的含义不仅仅是数据隐藏的,而是任何形式的隐藏.对数据和方法的封装――通过访问控制符;对子类和实现封装――通过抽象类和接口;对其他对象的封装――通过组合.而这一切都是为了最终的一个目的――封装变化.
自言自语了半天,大家可能在想:"该同志到底想说什么呢?".图穷匕见之后,问题的关键是――什么能够让我们从"面向过程的OO"和"过早处理细节"的"暴政"中解放出来呢?什么能够让我们更深层次去理解OO呢?回答当然是"设计模式",它将给你一个更高的层次的对于问题,设计过程和面向对象的视角. GoF(Gang of four <<设计模式>>的四个作者)已经给了我们所有问题的答案:
------ 针对接口编程.
------ 优先考虑组合而不是继承.
------ 发现并封装变化.
但之所以提出上面的那些问题,是想让大家以软件开发的不同视角去学习"设计模式",我们应该用模式来帮助我们进行设计,而不是用设计模式简单的把一些类粘合在一起,这是刚开始学习设计模式的人常见的做法.当然 ,这里不可能详细介绍GoF的23种设计模式(呵呵,吝啬的编辑不会给我那么多豆腐块!).正如Alexander(建筑学家)所说:"在最后的阶段,模式已经不再重要……",这里只是想让大家以正确的角度去学习设计模式,真正的thinking in OO!
参考书目:《设计模式精解》Alan Shalloway James R.Trott
《设计模式:可复用面向对象软件的基础》第二版GoF