C#与面向对象编程语言.pdf
《C#与面向对象编程语言.pdf》由会员分享,可在线阅读,更多相关《C#与面向对象编程语言.pdf(22页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第第2章章 C#与面向对象编程语言与面向对象编程语言 阅读目标阅读目标 树立面向对象设计思想 理解封装、继承、抽象、多态的概念 学会如何识别系统中的对象 2.1 面向对象思想面向对象思想 面向对象思想为软件设计与开发赋予了哲学的意义。在哲学的世界里,小至沙粒微尘,大至日月星辰乃至宇宙,均可视为单独的个体对象而存在。如果以哲学的目光凝视程序的世界,又何尝不是如此?一个用户,一种销售策略,一条消息,一张订单,一个Web网页,运用面向对象思想,则它们都可以视为一种对象。每一种对象,都有独立的生命周期。谁来创建它,谁来销毁它,它的内在属性,表现行为,以及它与外界之间的关系和集合,无不具有某种哲学的意味
2、。我们在定义对象时,就好比是在描述一个现实世界的事物,需要第 2 章 C#与面向对象编程语言 21 定义该对象的自然属性和社会属性,限定它的内涵与外延,勾勒出该对象的社会关系。面向对象思想的精要,在于“一切皆为对象”的本质。那么,什么是对象呢?一般认为,对象是一个真实的或抽象的元素,它包含了描述信息的属性以及处理对象信息的行为。行为在对象的定义时,又表现为方法。以现实世界为例,“人”作为一种特殊的动物,可以看作是一种对象。这个对象具有许多属性,例如姓名、身高、体重、民族、国籍、出生年月等等,而行为则包括行走、吃饭、跑步、乃至于玩游戏、踢足球。从词义学的角度来看,属性偏向于名词的范畴,行为则具有
3、动词的词性。虽然说对象是由属性和行为组成,但并不代表它们必须被对象同时拥有,仅仅拥有属性或者行为的对象在系统设计中比比皆是。之所以如此定义,或者是由对象的自身特质所决定,也可能根据设计的要求而定。例如,商品信息对象就只包含了商品名、商品类别、价格、库存量等属性,如果不考虑数据操作,对象自身是不具有任何行为的。在软件体系架构设计中,领域层的实体对象往往就是类似于商品信息对象这样仅具有属性的对象。而当我们在分辨鸟类动物时,有时候却需要将鸟类飞行的能力视为一种对象。此时,该对象仅具有飞行这样一种行为。或许它与我们有关对象的理解大相径庭,然而基于“一切皆为对象”的本质,为什么我们不能对其一视同仁呢?对
4、象的属性与行为并非一成不变,根据实际情况,同一种对象具有的属性和行为可能会发生变化。例如同样是对象“人”,在户籍管理系统中,我们就不必关心有关行走、吃饭、跑步等行为;但如果是开发一个足球游戏,那么作为对象的“人”,就需要定义各种踢足球的行为。同样,在户籍管理系统中,不必考虑对象“人”的身高、体重、容貌等属性,但如果是征婚信息管理系统中,这些属性恰恰是系统最为关注的焦点。在进行面向对象设计时,开发者就是造物主,是抟土造人的女娲,对象的一切要素均掌握在开发者手中。然而,一个好的开发者却不能随心所欲的“创造”对象,他们应该是系统需求的忠实执行者,对象的属性与行为,特别是对象的细粒度都必须由系统需求决
5、定。以“汽车”对象为例,对于车辆管理系统而言,汽车被看作是一个整体,我们不需要对汽车的零部件进行细化。如果是汽车的生产控制系统,“汽车”对象则是一整套零部件的集合。我们在定义对象时,必须细化到引擎、轮胎乃至于更小的一级。对象的定义必须符合系统的需求,这是面向对象设计中最基本的原则。面向对象思想还包括三个核心要素,即封装(Encapsulation)、继承(Inheritance)与多态(Polymorphism),C#编程极限 22它将面向对象技术推到了思想的境界。只有真正理解了这三个要素,才算得上掌握了面向对象思想的精髓。所谓对象的“封装”,就是将对象的相关数据隐藏到接口方法中。之所以要采用
6、封装,是因为对象会引人而异,暴露出不同的数据信息。反过来说,对象的封装则有利于相关信息的隐藏,它适当地保护了对象的“隐私”。正如一间房屋一般,室内的装饰与摆设只能被室内的居住者欣赏与使用,如果没有四面墙的遮挡,室内的所有活动在外人面前一览无遗,结果就太糟糕了。然而,封装是有限度的,一个包裹得严严实实的黑箱子,即使它的空间再宽阔,也没有实用价值。正如房屋的门与窗,就是封装对象暴露在外的接口方法,专门供人出入与流通空气、为房间带来一缕阳光。“封装”的意义在于除了设计者之外,对象不能将任何实现细节暴露在外。以电子商务系统为例,系统的设计者必须根据业务逻辑实现提交订单的所有细节,但这些细节对于客户而言
7、,却是没有必要的。客户并不关心提交订单的处理流程,他只需要知道如何提交订单,以及订单是否提交正确。对象的封装使得信息不至于造成冗余,减小了客户需要关注的信息量。“继承”是一个漂亮的隐喻,它将法律中的术语生动地引入到面向对象思想中,就像继承遗产一般,有效地保证了被继承者的所有特性在继承者中得以复用与延续。对象的继承,代表了资源的重利用,通过继承可以省去许多重复的实现,减少了开发的代码量。例如“人”对象与“雇员”对象,“雇员”对象就完全具备对象“人”的所有属性和行为。此时,我们就可以使“雇员”对象继承自“人”对象,使得我们可以不用重复实现“雇员”对象中和“人”对象相同的属性与行为,完成了代码的复用
8、。对象的继承代表了一种“is-a”的关系,如果两个对象 A 和 B,可以描述为“B 是 A”,则表明 B 可以继承 A。例如“雇员是人”,就说明了雇员与人之间继承与被继承的关系。实际上,继承者还可以理解为是对被继承者的特殊化,因为它除了具备被继承者的特性外,还具备自己独有的个性。例如,雇员就可能拥有工资、考勤等“人”对象所不具备的属性。因而,在继承关系中,继承者可以完全替换被继承者,反之则不成立。所以,我们在描述继承的“is-a”关系时,是不能相互颠倒的。试想,我们能够理直气壮地说“人是雇员”吗?对象的继承并不一定代表自上而下的设计过程。虽然在大部分情况下,我们都是先定义父对象,然而再定义继承
9、于它的子对象;但有时候我们也需要反其道而行之,在定义了第 2 章 C#与面向对象编程语言 23 一系列相近的对象后,从中抽象出它们共同的父对象。例如,对于排序对象而言,我们可以先定义冒泡排序、快速排序、二叉排序等多个对象,分别实现各自的排序算法。当我们意识到调用者在调用这些排序对象时,仅需要关注排序行为的定义,而与排序算法的实现无关时,就有必要为它们抽象出一个统一的排序对象。排序对象的抽象并非完全出于代码复用的目的,更重要的是它可以将复杂的实现逻辑简化,从而让调用者化繁为简,集中到排序算法的定义上。正如人的行走,并不需要具体去考虑手、脚、腿、臂以及腰的配合,我们只需要给大脑一个指令我要行走,大
10、脑就会按照你的要求控制这些器官,完成你行走的要求。对象的抽象符合道家的思想,一为万物,抽象代表具体,就代表了无限多种可能。抽象的意义就好比这样一则故事所述。说三个秀才到省城参加乡试。临行前三人都对自己能否中举惴惴不安,于是求教于街头的算命先生。算命老者的目光在这三人的脸上逡巡良久,最后徐徐伸出一个手指,就闭上眼睛不再言语,一付高深莫测的模样。三人纳闷,给了银子,带着疑惑到了省城参加考试。发榜之日,三人联袂去看成绩,得知结果后,三人齐叹,算命先生真乃神人矣!抽象就是算命先生的“一指禅”,一个指头代表了四种完全不同的含义。是一切人高中,还是一个都不中?是一个人落榜,还是一个人高中?算命先生并不能未
11、卜先知,因此只能给出一个包含了所有可能却没有实现的答案,至于是哪一种结果,就留给三个秀才去慢慢琢磨吧。对象的抽象正是如此,抽象对象只有定义,而实现细节则由继承或实现了抽象对象的具体对象完成。对象的多态将封装、继承与抽象结合起来,它代表同一个对象可以在不同时期表现为不同的类型。多态利用封装的原理,定义了对象的类型,又通过继承保证了不同类型之间的关系,而抽象则保证了对象多态的能力。在面向对象思想中,对象代表我们能够在系统中分辨出的一切元素,是具有属性和行为的个体。表现在语言中,则体现为类型的一个实例。所谓“类型”,就是定义对象的格式,而实例则是按照规定的语法创建并存放在内存空间的具体对象。它具有自
12、己的生命周期,调用者通过它调用对象的属性与方法。类型与实例的关系,就好比“大侠”与“郭靖”的关系。“大侠”是江湖中所有行侠仗义、除恶惩奸的侠客的统称。而“郭靖”则是一个具体的大侠,是被称为“侠之大者”的武林高手。对象、类型、实例 C#编程极限 24我们可以认为“郭靖”是行走在江湖中的对象,它的类型是“大侠”。每一种语言都有创建实例的方法,在 C#中,通过 new 操作符完成。例如:大侠 郭靖=new 大侠();当创建了“大侠”的实例后,就可以通过实例调用对象的实例方法,例如:郭靖.行侠仗义();仍然可以用之前的故事来理解对象的多态,例如算命先生的答案,就是对象多态的表现形式。因为这个答案在不同
13、的情形下,可以有不同的理解。如果将四种可能的解答都看作是继承了抽象的具体类型,则最后的答案就可能根据实际情况的不同成为这四种答案中的一种。此时,一个手指代表一种抽象,而这四个答案则与该抽象形成一种继承关系,并通过封装将具体的实现与暴露的接口定义完全分开。抽象的整个结构如图 2-1 所示:图 2-1 算命先生的答案 图 2-1 是 UML 类图的表现形式,它代表了四种答案的抽象。我们可以利用如下的方式创建抽象对象的实例:Answer answer;if(全部高中)answer=new AllPass();if(全部落榜)answer=new AllFail();if(一个高中)answer=ne
14、w OnePass();if(一个落榜)answer=new OneFail();answer.Pass();第 2 章 C#与面向对象编程语言 25 不管是何种情况,answer 实例的定义类型始终是 Answer 类型,这正是基于抽象与继承为前提。至于多态的体现则在于 answer 对象能够根据不同的情况被实例化为不同类型的对象,从而在执行 Pass 方法时,表现出不同的意义。UML(Unified Modeling Language,统一建模语言)是专门用于软件建模的通用语言,创始人是 Jim Rumbaugh、Ivar Jacobson 和 Grady Booch。UML 制定了统一的
15、标准建模符号,以表示程序设计特别是面向对象程序设计中的基本要素,从而为客户需求、系统架构提供清晰直观的设计。UML 的一个重要作用是有利于程序员之间的交流,促进对程序结构的理解。UML 模型图主要包括用例图、类图、时序图、状态图、活动图、组件图和部署图。UML 是程序员在进行软件设计时必不可少的工具,是必须掌握的众多技能之一。若欲了解更多有关 UML 的知识,可以参考 Martin Fowler 所著的 UML 精粹 以及 Craig Larman 所著的 Applying UML and Patterns。多态保证了程序的灵活性,因为它将对象形态的决定权交给了调用者。这里有一个动态绑定的问题
16、。为什么对象可以在不同时期表现为不同的类型呢?原因在于它利用了继承的可替代性,通过在运行期间,将父对象类型替换为子对象类型,从而达到类型转换的目的,动态绑定为具体对象。因此,调用者可以根据系统需求,创建不同类型的实例,只要该实例被统一抽象为相同的父类型。以驾驶汽车为例,无论是手动档还是自动档,驾驶方式都是相同的,区别仅在于内部的驱动方式。此时,我们就可以对汽车驾驶的行为进行抽象,定义统一的驾驶行为。因而,无论驾驶人员是操作手动档,还是自动档,表现的驾驶行为都是一致的。当驾驶人员根据自身的熟练情况改变自动档为手动档时,并不影响汽车零部件的外在布局与设计。多态还保证了程序的稳定性。由于抽象抹去了具
17、体实现细节的差异,使得调用者不因实现细节的变化而改变原来定义的抽象类型,从而达到了隔离变化的目的。这一点非常重要,因为在程序设计过程中,我们最难掌控的就是需求的变化。对变化实现隔离,就可以保证程序对需求变化的依赖最小。简明地说,对象的封装、继承与多态保证了对象的高内聚低耦合,有利于软件模块的可复用,保证了程序的可扩展,而这正是面向对象思想体现在软件设计中最大的优势。什么是 UML?C#编程极限 26面向对象思想博大精深,非三言两语所能说清。要建立这样一种思想,存乎于你的内心,是一种“妙悟”。也许在你写了几百个小程序之后还没能体会到面向对象的真谛,但是在霎那之间,你却突然明白了,顿有一种拨开云开
18、见月明的喜悦。我不是故意卖弄玄虚,有时候开发软件还真需要那么一点灵感,有人说,编程是一门艺术,我同意。那么这种“妙悟”什么时候能来到,我无法确知答案,这需要你的体悟。不过这种体悟与谈禅无关,不是每天冥想就可以的,需要我们脚踏实地地编写程序、开发项目,然后自然会有所体悟。正所谓,读书百遍,其义自现。2.2 识别系统中的对象识别系统中的对象 要掌握面向对象思想,首先必须具备识别系统中对象的能力。这包含两个含义。其一是分辨我们需要定义的对象,其二则是划分对象的界限,明确对象应该具备哪些属性和方法。对象的识别必须结合客户需求和业务逻辑,根据系统要求实现的功能出发。例如,我们要求开发一个电子商务系统,功
19、能要求如下:支持商品的查询功能;用户如需购买商品,需要成为注册用户并登录;如果当前库存无该商品,用户可以预订;用户可以将商品放入购物车;用户购买商品之前,需提交订单;用户提交订单后,系统应将订购信息发送邮件给用户;用户可以对商品添加评论。识别对象的一个简单办法是寻找功能描述中的关键名词,如商品、用户、购物车、订单、邮件、评论。这些名词大致与电子商务系统的主要对象一一对应。界定对象的属性需要分析系统对该对象的要求以及所需要的信息。例如商品对象,就应该包括商品名、商品编号、价格、商品图片、所属类别、生产厂商、库存量等等。决定属性的一个重要因素是第 2 章 C#与面向对象编程语言 27 业务。对于大
20、多数电子商务系统而言,上述属性已经涵盖了商品的主要特性。但如果业务要求提供更细致的商品信息查询服务,就可能需要定义商品的扩展属性。这些属性可能与商品的类别有关。例如商品的类别为衣服,就应该定义衣物的样式、颜色、型号等。如果类别是书籍,就需要提供作者信息、内容介绍、出版社信息等。关于对象行为的定义,我们可以从功能描述中寻找与这些对象名词相关联的动词。例如查询商品,就代表商品对象具有 Search 方法。用户注册与登录,则代表用户对象具有Register 和 SignIn 方法。除了关注对象的属性与方法外,我们还必须分析对象之间的关系。例如订单与商品之间就存在一对多的关系,用户与订单的关系,同样存
21、在一对多的关系。这种关系的获得在对象的定义上,可以表现为对象的属性或行为。例如对于用户对象而言,就可以定义 Orders属性或者 GetOrders 方法,用以获取该用户的所有订单。对象的识别在软件设计过程中并非一蹴而就,随着设计者对需求更加深入的理解,或者随着客户需求的变更,我们应该不断地调整对象的定义,并合理地利用抽象、继承、多态等技术完成软件结构的修改与完善。例如用户对象的定义。如果客户要求将用户分为会员与 VIP 会员,就需要调整原有的设计,增加两个新的对象 Member 和 VIPMember,同时使其继承原来的用户对象 User。此外,由于系统要求提供邮件发送服务,我们就有必要引入
22、一个专门的服务对象 EmailService,负责实现电子邮件的发送。还有一些好的方法可以有效地帮助我们识别对象。例如利用UML编写用例(User Case)以帮助我们分析客户需求,识别系统中的对象,然后通过建立类图表述类对象的定义以及它们之间的关系,通过状态图表示对象状态的变化,通过时序图表示类对象之间的协作与交互。此外,我们还可以利用极限编程(Extreme Programming)中编写用户故事(User Story)的方式,完成对象的识别。极限编程是由 Kent Beck 提出的一种敏捷开发方法,是一种轻量级的软件工程方法学。极限编程推崇简单有效的开发方式,提倡只做目前你需要做的(Do
23、 the simplest thing that could possibly work!)若要了解更多有关极限编程的知识,可以阅读 Kent Beck 所著的解析极限编程:拥抱变化。极限编程(Extreme Programming)C#编程极限 28期望从一开始就能够完全掌握识别对象的方法,无疑是痴人说梦。识别对象的技巧虽然与方法有关,但更多的却是从设计经验中获得。然而,对于一个利用面向对象编程语言进行软件开发的程序员,如果能够从一开始就建立起面向对象思想,遵循“一切皆为对象”的原则,学会从软件开发中识别对象,无疑能够收到事半功倍之效。如果你认为面向对象思想过于艰深,可以想象一下现实世界对对
24、象的看法。至于对象的识别,我们完全可以将其看作是一种填字游戏,关键不在于答案是什么,乐趣全在游戏之中。2.3 C#的面向对象特征的面向对象特征 C#可以看作是一门纯粹的面向对象编程语言,它真正体现了“一切皆为对象”的精神。C#的程序文件由类型组成,例如类和接口,类型的成员则包括字段、方法、属性和事件。在 C#的类型中,哪怕是最简单的基本类型也都进行了对象的封装,并抽象出共同的基类System.Object 以实现这些对象共有的成员。例如,我们可以利用创建对象实例的方法,对基本数据类型对象进行初始化:int i=new int();i=100;这等同于直接对变量 i 赋值:int i=100;如
25、果我们已经熟悉了有关类的定义和实例化,可以发现定义 int 类型的变量 i 与类对象的创建是完全一致的。此外,我们还可以调用 int 对象的相关方法,例如 ToString 方法。实际上,它利用继承的方式复用了基类 Object 的方法:string str=i.ToString();C#的数据类型分为值类型与引用类型两种,包含的类型如表 2-1 所示:类别类别 描述描述 带符号整型:sbyte,short,int,long 值值 类类 简单类型 无符号整型:byte,ushort,uint,ulong 第 2 章 C#与面向对象编程语言 29 Unicode 字符型:char 浮点型:flo
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 面向 对象 编程 语言
限制150内