本文总结搜集面向对象思想资料,并结合本人的思索,力图能够加深对面向对象的理解。
面向对象的方法论:
来自c++primer第十章
面向对象是一种程序设计的概念性方法,面向对象最重要的特征是抽象、封装和数据隐藏、多态、继承、代码的可重用性。下面用一个例子来展示面向过程和面向对象程序设计的差别要编写一个程序用于记录垒球队的统计数据,涉及的数据包括队员姓名、击球次数、击中次数、命中率等。
如果采用面向过程的程序设计方法,那我们需要先输入这些球队的相关数据,因此我们可能需要一个函数专门来处理输入,输入或许从文件或许从控制台。在获取数据后,我们需要进行一些计算,比如命中率,这或许需要另一个用于计算的函数。计算完成后就是输出结果了,必然需要一个函数来格式化并输出结果。当一场新的比赛结束后,就要更新结果,我们不想重新来过,因此设计了一个函数用来更新已有的数据和输出结果。好了,现在考虑一下怎么表示这些数据呢?将每个队员的信息数据组织成一个结构体,然后用一个结构数组。简而言之,在采用面向过程的编程方法时,首先要考虑遵循的步骤,然后考虑如何表示这些数据。
如果采用面向对象的编程方法又如何?我们首先考虑数据:不仅考虑数据如何表示,还要考虑数据如何使用。我们要跟踪的是什么,当然是队员。因此需要有一个对象表示队员的方法面面。这将是基本数据单元——一个表示选手的基本信息和统计数据的对象。我们需要一些处理对象的方法:首先需要将信息数据加到该对象的方法,其次还需要一些计算数据(比如命中率)的方法,计算方法应当自动完成而无需用户的干涉,另外还得有数据更新新的方法。因此用户与数据交互有三种:初始化、更新和报告结果——这就是接口。简而言之,采用OOP的方法时,首先从用户的角度考虑——描述对象所需的数据以及描述用户与数据交互所需的操作。完成对接口的描述后,需要确定如何实现接口和数据存储。最后使用确定的方法实现程序。
我的评注: 在面向过程的方法中,我们头脑中首先出现的是类似流程图的的东西,而采用OOP我们头脑中首先出现的是类似对象关系图的东西。
来自百度百科
用传统的结构化方法开发大型软件系统涉及各种不同领域的知识,在开发需求模糊或需求动态变化的系统时,所开发出的软件系统往往不能真正满足用户的需要。用结构化方法开发的软件,其稳定性、可修改性和可重用性都比较差,这是因为结构化方法的本质是功能分解,从代表目标系统整体功能的单个处理着手,自顶向下不断把复杂的处理分解为子处理,这样一层一层的分解下去,直到仅剩下若干个容易实现的子处理功能为止,然后用相应的工具来描述各个最低层的处理。因此,结构化方法是围绕实现处理功能的“过程”来构造系统的。然而,用户需求的变化大部分是针对功能的,因此,这种变化对于基于过程的设计来说是灾难性的。用这种方法设计出来的系统结构常常是不稳定的 ,用户需求的变化往往造成系统结构的较大变化,从而需要花费很大代价才能实现这种变化。
我的评注:这种以软件功能作为出发点的设计方法难以应付一个重要事实,就是客户的需求可能发生调整,软件运行的环境也有可能发生变化。由于功能是层层划分的,这种变化往往使我们陷入牵一发而动全身的窘境。
面向对象是一种思想,是软件领域的世界观、方法论
面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOA,Object Oriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)。许多有关面向对象的文章都只是讲述在面向对象的开发中所需要注意的问题或所采用的比较好的设计方法。看这些文章只有真正懂得什么是对象,什么是面向对象,才能最大程度地对自己有所裨益。这一点,恐怕对初学者甚至是从事相关工作多年的人员也会对它们的概念模糊不清。
很多人没有区分“面向对象”和“基于对象”两个不同的概念。面向对象的三大特点(封装,继承,多态)缺一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。现在的很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象”都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些,的确很饶口。
从事面向对象编程的人按照分工来说,可以分为“类库的创建者”和“类库的使用者”。使用类库的人并不都是具备了面向对象思想的人,通常知道如何继承和派生新对象就可以使用类库了,然而我们的思维并没有真正的转过来,使用类库只是在形式上是面向对象,而实质上只是库函数的一种扩展。
面向对象是一种思想,是我们考虑事情的方法,通常表现为我们是将问题的解决按照过程方式来解决呢,还是将问题抽象为一个对象来解决它。很多情况下,我们会不知不觉的按照过程方式来解决它,而不是考虑将要解决问题抽象为对象去解决它。有些人打着面向对象的幌子,干着过程编程的勾当。
我的评注:必须在一开始就运用面向对象的方法来分析问题,而不是依据所需功能到对象库里面寻找所需的对象进行派生扩展。再用过程性的方法来使用这些类。
什么阻碍了我们理解面向对象的思想:
CPU作为计算机的大脑,不断循环地读取下一条指令并执行,这个过程是如此的严格以至给了计算机系的学生们强烈的暗示,我们必须确保我们的代码每个步骤都准确无误。因此在初学编程的阶段,我们总是将主要的精力放在检查代码的逻辑过程上,逻辑判断是否正确,条件分支是否足够,算法的步骤是否清晰无误。没有办法,谁叫计算机本身就是个类似面向过程的东西呢?我们只得将我们的代码排列好等待CPU的检阅。
我们必须要理解计算机的工作方式,在编写程序的初级阶段采用面向过程的方式也无可厚非。但这往往导致我们后来要耗费更多的脑细胞来摆脱“过程”对我们的束缚,以达到对OOP的真正理解。现实世界本来就是有各种对象组成的,为了编写程序,我们偏偏要把它理解成一个个过程,然后为了更好地编写程序,又要回归现实——采用OOP。
我认为计算机是一个面向过程的设备,从这个角度较,我们的程序也应该是面向过程的。但程序是由人编写的,人眼中世界是面向对象的。这是一对矛盾体,解决这个矛盾的关键先进的编程方法——OOP以及对OOP有良好支持的编译器。OOP希望我们以更人性化、更接近现实的方式来编写程序,这样产生的程序更能适应客观世界的变化,而编译器会替计算机产生它所期望的指令过程。为了达到这种完美的转换,编译器默默地做了许多时,产生了许多我们看不见的代码和数据,因此OOP会相对地让程序损失一些效率。因此只有计算机性能达到一定程度我们才能享受OOP带来的好处;而在这种条件下,这种性能的损失是完全值得的,因为OOP使程序更容易编写、维护,如果仅仅为了并不重要的性能提升而将程序设计地难以编写、难以维护又有什么意义?
一边是面向过程的计算机,一边是面向对象的现实世界,OOP必然要在这两者之间寻求交互和平衡。抱着这种出发点,希望能够理解OOP的方方面面。
面向对象的本质和面向对象的程序语言:
面向对象的本质是什么?答案是抽象。从面对的问题域抽象出解决问题所需的对象是面向对象方法的核心思想。能否恰当抽象出足够的对象类型,特别是抽象出潜在的对象是决定软件设计好坏的关键。如果从更宽泛的角度讲,对我们所面对的复杂问题进行抽象,抓住本质,得出高度精炼的逻辑模型,对问题的求解具有重要的意义。从这个角度来说,抽象并不仅仅局限于对象的抽象,也包括流程和更高层的系统结构。
而封装、继承、多态是面向对象的特征,这是采用面向对象的方法所能够达到的效果。注意区分特点和本质。
而面向对象的程序语言应该为实现面向对象的本质和特征提供支持。我们说一种语言是面向对象的,实际上是对它对面向对象的软件是想提供了支持。因此C++的虚函数、多重继承和面向对象之间并没有什么必然的联系,不过是此种语言用以支持多态和继承的手段选择罢了。
面向对象的模型:
下面通过UML各类图的介绍,说明各种对象模型及其特点。--摘自《标准建模语言UML教程》
客观世界是一个复杂巨大的系统,需要从不同的角度来考察,才能真正理解这个系统。为了能支持从不同角度来考察系统,UML定义了以下5类、10种模型图。
第一类是用例图,它从用户角度描述系统的功能,并指出各功能的操作者。
第二类是静态图,包括类图,对象图和包图。其中类图用于定义系统中的类,包括描述类之间的联系(如关联、依赖、聚合等)以及类的内部结构,即类的属性和操作。因此类图描述系统中类的静态结构,它描述的是一种静态关系,在系统的整个生命周期都是有效的。对象图所使用的表示符号与类图几乎相同,它们的不同点在于对象图只显示类的对象实例,而不是实际的类。 一个对象图是类图的一个实例。由于对象有生命周期,所以对象图只在系统的某段时间有效。包图由包或类组成,主要表示包与包或包与类之间的关系,包图用于描述系统的分层结构。
第三类是行为图,描述系统的动态模型和对象间的交互关系。一种是状态图,它描述一类对象可能的状态以及事件发生时状态迁移的条件。通常状态图是对类图的补充,我们并不需要对所有的类绘制状态图,而只要为那些有多个状态,并且其行为受外界影响而会发生改变的类绘制状态图。另一种称为活动图,它描述为满足用例要求所要进行的活动及活动见的约束关系,使用活动图可以方便地表示并进行活动。
第四类是交互图,它描述对象间的交互关系。一种称之为顺序图,用以描述对象间的动态合作关系,它强调对象之间消息发送的顺序,同时也显示对象之间的交互过程。另一种是合作图,它着重描述对象间的协作关系。合作图和顺序图类似,显示对象间的动态合作关系。除了显示信息交换外,合作图还显示对象以及对象之间的关系。如果强调时间和顺序,应当使用顺序图;如果强调通信关系,则可以选择合作图,这两种图合称为交互图。
第五类是实现图,包括构件图和配置图。构件图描述代码部件的物理结构和各部件之间的依赖关系。一个部件肯能是一个资源代码部件、一个二进制部件或一个可执行部件,它包含逻辑类和实现类的有关信息。构件图有助于分析和理解部件之间的相互影响程度。配置图定义系统中的软硬件物理体系结构,它可以显示实际的计算机和设备(用节点表示)以及它们之间的连接关系,也可以显示连接的类型和部件或部件之间的依赖性。在节点内部,放置可执行的部件和对象,以显示节点和可执行单元之间的对应关系。
这些图为系统的分析、开发提供了多种图形表示。它们的有机结合就有可能分析构造一个一致的系统。从应用的角度看,当采用面向对象技术设计系统时,首先是描述需求,次之根据需求建立系统的静态模型,以构造系统的结构,第三步是描述系统的行为,在第一步与第二步所建立的模型都是静态的,包括用例图、类图(包括包图)、对象图、构件图和配置图。第三步建立的模型或者可以执行或者表示执行时的时序状态或交互关系,它包括状态图、活动图、顺序图和合作图等四种图。
依赖关系与关联关系:关联关系是一种比依赖要强的关系,表示两个对象之间存在天然的、本质上的关联,它分为组合和聚合两种。而依赖关系表示一个类对象可能在某些功能上依赖于另一个类对象,当然从这个角度讲关联也是一种依赖,但UML通过区分它们来提供更清晰的模型。我个人认为区分这两种关系还有一个好处就是,关联关系往往在类设计阶段就凸现出来,直接体现了我们所设计的模型结构,是我们要特别关注的类关系,而大部分依赖关系往往到实现阶段才会体现,实际画类图时,为了突出重点,上大部分的依赖关系我们都不怎么关注。