您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 咨询培训 > C#与面向对象编程语言
第2章C#与面向对象编程语言阅读目标树立面向对象设计思想理解封装、继承、抽象、多态的概念学会如何识别系统中的对象2.1面向对象思想面向对象思想为软件设计与开发赋予了哲学的意义。在哲学的世界里,小至沙粒微尘,大至日月星辰乃至宇宙,均可视为单独的个体对象而存在。如果以哲学的目光凝视程序的世界,又何尝不是如此?一个用户,一种销售策略,一条消息,一张订单,一个Web网页……,运用面向对象思想,则它们都可以视为一种对象。每一种对象,都有独立的生命周期。谁来创建它,谁来销毁它,它的内在属性,表现行为,以及它与外界之间的关系和集合,无不具有某种哲学的意味。我们在定义对象时,就好比是在描述一个现实世界的事物,需要第2章C#与面向对象编程语言21定义该对象的自然属性和社会属性,限定它的内涵与外延,勾勒出该对象的社会关系。面向对象思想的精要,在于“一切皆为对象”的本质。那么,什么是对象呢?一般认为,对象是一个真实的或抽象的元素,它包含了描述信息的属性以及处理对象信息的行为。行为在对象的定义时,又表现为方法。以现实世界为例,“人”作为一种特殊的动物,可以看作是一种对象。这个对象具有许多属性,例如姓名、身高、体重、民族、国籍、出生年月等等,而行为则包括行走、吃饭、跑步、乃至于玩游戏、踢足球。从词义学的角度来看,属性偏向于名词的范畴,行为则具有动词的词性。虽然说对象是由属性和行为组成,但并不代表它们必须被对象同时拥有,仅仅拥有属性或者行为的对象在系统设计中比比皆是。之所以如此定义,或者是由对象的自身特质所决定,也可能根据设计的要求而定。例如,商品信息对象就只包含了商品名、商品类别、价格、库存量等属性,如果不考虑数据操作,对象自身是不具有任何行为的。在软件体系架构设计中,领域层的实体对象往往就是类似于商品信息对象这样仅具有属性的对象。而当我们在分辨鸟类动物时,有时候却需要将鸟类飞行的能力视为一种对象。此时,该对象仅具有飞行这样一种行为。或许它与我们有关对象的理解大相径庭,然而基于“一切皆为对象”的本质,为什么我们不能对其一视同仁呢?对象的属性与行为并非一成不变,根据实际情况,同一种对象具有的属性和行为可能会发生变化。例如同样是对象“人”,在户籍管理系统中,我们就不必关心有关行走、吃饭、跑步等行为;但如果是开发一个足球游戏,那么作为对象的“人”,就需要定义各种踢足球的行为。同样,在户籍管理系统中,不必考虑对象“人”的身高、体重、容貌等属性,但如果是征婚信息管理系统中,这些属性恰恰是系统最为关注的焦点。在进行面向对象设计时,开发者就是造物主,是抟土造人的女娲,对象的一切要素均掌握在开发者手中。然而,一个好的开发者却不能随心所欲的“创造”对象,他们应该是系统需求的忠实执行者,对象的属性与行为,特别是对象的细粒度都必须由系统需求决定。以“汽车”对象为例,对于车辆管理系统而言,汽车被看作是一个整体,我们不需要对汽车的零部件进行细化。如果是汽车的生产控制系统,“汽车”对象则是一整套零部件的集合。我们在定义对象时,必须细化到引擎、轮胎乃至于更小的一级。对象的定义必须符合系统的需求,这是面向对象设计中最基本的原则。面向对象思想还包括三个核心要素,即封装(Encapsulation)、继承(Inheritance)与多态(Polymorphism),C#编程极限22它将面向对象技术推到了思想的境界。只有真正理解了这三个要素,才算得上掌握了面向对象思想的精髓。所谓对象的“封装”,就是将对象的相关数据隐藏到接口方法中。之所以要采用封装,是因为对象会引人而异,暴露出不同的数据信息。反过来说,对象的封装则有利于相关信息的隐藏,它适当地保护了对象的“隐私”。正如一间房屋一般,室内的装饰与摆设只能被室内的居住者欣赏与使用,如果没有四面墙的遮挡,室内的所有活动在外人面前一览无遗,结果就太糟糕了。然而,封装是有限度的,一个包裹得严严实实的黑箱子,即使它的空间再宽阔,也没有实用价值。正如房屋的门与窗,就是封装对象暴露在外的接口方法,专门供人出入与流通空气、为房间带来一缕阳光。“封装”的意义在于除了设计者之外,对象不能将任何实现细节暴露在外。以电子商务系统为例,系统的设计者必须根据业务逻辑实现提交订单的所有细节,但这些细节对于客户而言,却是没有必要的。客户并不关心提交订单的处理流程,他只需要知道如何提交订单,以及订单是否提交正确。对象的封装使得信息不至于造成冗余,减小了客户需要关注的信息量。“继承”是一个漂亮的隐喻,它将法律中的术语生动地引入到面向对象思想中,就像继承遗产一般,有效地保证了被继承者的所有特性在继承者中得以复用与延续。对象的继承,代表了资源的重利用,通过继承可以省去许多重复的实现,减少了开发的代码量。例如“人”对象与“雇员”对象,“雇员”对象就完全具备对象“人”的所有属性和行为。此时,我们就可以使“雇员”对象继承自“人”对象,使得我们可以不用重复实现“雇员”对象中和“人”对象相同的属性与行为,完成了代码的复用。对象的继承代表了一种“is-a”的关系,如果两个对象A和B,可以描述为“B是A”,则表明B可以继承A。例如“雇员是人”,就说明了雇员与人之间继承与被继承的关系。实际上,继承者还可以理解为是对被继承者的特殊化,因为它除了具备被继承者的特性外,还具备自己独有的个性。例如,雇员就可能拥有工资、考勤等“人”对象所不具备的属性。因而,在继承关系中,继承者可以完全替换被继承者,反之则不成立。所以,我们在描述继承的“is-a”关系时,是不能相互颠倒的。试想,我们能够理直气壮地说“人是雇员”吗?对象的继承并不一定代表自上而下的设计过程。虽然在大部分情况下,我们都是先定义父对象,然而再定义继承于它的子对象;但有时候我们也需要反其道而行之,在定义了第2章C#与面向对象编程语言23一系列相近的对象后,从中抽象出它们共同的父对象。例如,对于排序对象而言,我们可以先定义冒泡排序、快速排序、二叉排序等多个对象,分别实现各自的排序算法。当我们意识到调用者在调用这些排序对象时,仅需要关注排序行为的定义,而与排序算法的实现无关时,就有必要为它们抽象出一个统一的排序对象。排序对象的抽象并非完全出于代码复用的目的,更重要的是它可以将复杂的实现逻辑简化,从而让调用者化繁为简,集中到排序算法的定义上。正如人的行走,并不需要具体去考虑手、脚、腿、臂以及腰的配合,我们只需要给大脑一个指令——我要行走,大脑就会按照你的要求控制这些器官,完成你行走的要求。对象的抽象符合道家的思想,一为万物,抽象代表具体,就代表了无限多种可能。抽象的意义就好比这样一则故事所述。说三个秀才到省城参加乡试。临行前三人都对自己能否中举惴惴不安,于是求教于街头的算命先生。算命老者的目光在这三人的脸上逡巡良久,最后徐徐伸出一个手指,就闭上眼睛不再言语,一付高深莫测的模样。三人纳闷,给了银子,带着疑惑到了省城参加考试。发榜之日,三人联袂去看成绩,得知结果后,三人齐叹,算命先生真乃神人矣!抽象就是算命先生的“一指禅”,一个指头代表了四种完全不同的含义。是一切人高中,还是一个都不中?是一个人落榜,还是一个人高中?算命先生并不能未卜先知,因此只能给出一个包含了所有可能却没有实现的答案,至于是哪一种结果,就留给三个秀才去慢慢琢磨吧。对象的抽象正是如此,抽象对象只有定义,而实现细节则由继承或实现了抽象对象的具体对象完成。对象的多态将封装、继承与抽象结合起来,它代表同一个对象可以在不同时期表现为不同的类型。多态利用封装的原理,定义了对象的类型,又通过继承保证了不同类型之间的关系,而抽象则保证了对象多态的能力。在面向对象思想中,对象代表我们能够在系统中分辨出的一切元素,是具有属性和行为的个体。表现在语言中,则体现为类型的一个实例。所谓“类型”,就是定义对象的格式,而实例则是按照规定的语法创建并存放在内存空间的具体对象。它具有自己的生命周期,调用者通过它调用对象的属性与方法。类型与实例的关系,就好比“大侠”与“郭靖”的关系。“大侠”是江湖中所有行侠仗义、除恶惩奸的侠客的统称。而“郭靖”则是一个具体的大侠,是被称为“侠之大者”的武林高手。对象、类型、实例C#编程极限24我们可以认为“郭靖”是行走在江湖中的对象,它的类型是“大侠”。每一种语言都有创建实例的方法,在C#中,通过new操作符完成。例如:大侠郭靖=new大侠();当创建了“大侠”的实例后,就可以通过实例调用对象的实例方法,例如:郭靖.行侠仗义();仍然可以用之前的故事来理解对象的多态,例如算命先生的答案,就是对象多态的表现形式。因为这个答案在不同的情形下,可以有不同的理解。如果将四种可能的解答都看作是继承了抽象的具体类型,则最后的答案就可能根据实际情况的不同成为这四种答案中的一种。此时,一个手指代表一种抽象,而这四个答案则与该抽象形成一种继承关系,并通过封装将具体的实现与暴露的接口定义完全分开。抽象的整个结构如图2-1所示:图2-1算命先生的答案图2-1是UML类图的表现形式,它代表了四种答案的抽象。我们可以利用如下的方式创建抽象对象的实例:Answeranswer;if(全部高中)answer=newAllPass();if(全部落榜)answer=newAllFail();if(一个高中)answer=newOnePass();if(一个落榜)answer=newOneFail();answer.Pass();第2章C#与面向对象编程语言25不管是何种情况,answer实例的定义类型始终是Answer类型,这正是基于抽象与继承为前提。至于多态的体现则在于answer对象能够根据不同的情况被实例化为不同类型的对象,从而在执行Pass方法时,表现出不同的意义。UML(UnifiedModelingLanguage,统一建模语言)是专门用于软件建模的通用语言,创始人是JimRumbaugh、IvarJacobson和GradyBooch。UML制定了统一的标准建模符号,以表示程序设计特别是面向对象程序设计中的基本要素,从而为客户需求、系统架构提供清晰直观的设计。UML的一个重要作用是有利于程序员之间的交流,促进对程序结构的理解。UML模型图主要包括用例图、类图、时序图、状态图、活动图、组件图和部署图。UML是程序员在进行软件设计时必不可少的工具,是必须掌握的众多技能之一。若欲了解更多有关UML的知识,可以参考MartinFowler所著的《UML精粹》以及CraigLarman所著的《ApplyingUMLandPatterns》。多态保证了程序的灵活性,因为它将对象形态的决定权交给了调用者。这里有一个动态绑定的问题。为什么对象可以在不同时期表现为不同的类型呢?原因在于它利用了继承的可替代性,通过在运行期间,将父对象类型替换为子对象类型,从而达到类型转换的目的,动态绑定为具体对象。因此,调用者可以根据系统需求,创建不同类型的实例,只要该实例被统一抽象为相同的父类型。以驾驶汽车为例,无论是手动档还是自动档,驾驶方式都是相同的,区别仅在于内部的驱动方式。此时,我们就可以对汽车驾驶的行为进行抽象,定义统一的驾驶行为。因而,无论驾驶人员是操作手动档,还是自动档,表现的驾驶行为都是一致的。当驾驶人员根据自身的熟练情况改变自动档为手动档时,并不影响汽车零部件的外在布局与设计。多态还保证了程序的稳定性。由于抽象抹去了具体实现细节的差异,使得调用者不因实现细节的变化而改变原来定义的抽象类型,从而达到了隔离变化的目的。这一点非常重要,因为在程序设计过程中,我们最难掌控的就是需求的变化。对变化实现隔离,就可以保证程序对需求变化的依赖最小。简明地说,对象的封装、继承与多态保证了对象的高内聚低耦合,有利于软件模块的可复用,保证了程序的可扩展,而这正是面向对象思想体现在软件设计中最大的优势。什么是UML?C#编程极限26面向对象思想博大精深,非三言两语所能说清。要建立这样一种思想,存乎于你的内心,是一种“妙悟”。也许在你写了几百个小程序之后还没能体会到面向对象的真谛,但是在霎那之间,你却突然明白了,顿有一种拨开云
本文标题:C#与面向对象编程语言
链接地址:https://www.777doc.com/doc-4598324 .html