前言
面向对象的本质
:通过对象之间的协作完成功能。
面向对象的特点
:采用封装、继承、多态和抽象等设计方法。
面向过程和面向对象开发中,在分析问题
上的不同:
- 面向过程:拿到问题分析问题如何解决的步骤;
- 面向对象:拿到问题分析问题中有哪些类,类的属性与方法,类与类之间的关系。
- 面向对象遵循:合适的方法应该出现在合适的类中。
一、面向对象要解决的问题
1、 软件重用性差
重用性是在不经过修改或稍加修改就可反复使用的特性。软件重用性是软件工程追求的目标之一。
2、软件可维护性差
在软件开发过程中,始终强调软件的可读性、可修改性、可测试性是软件的重要质量指标。
3、不能满足用户需求
传统结构化方法开发的软件,在需求动态变化时,无法满足用户需求变化的情况。
二、面向对象的基本概念
基本概念 | 说明 |
---|---|
对象 | 万物皆可对象,一个整数或一架飞机,一个人,还可表示抽象的规则、事件等 |
对象的状态和行为 | 对象的状态就是属性,属性就是一个值,行为就是对象的操作或动作 |
类 | 类是相同或相似对象的抽象,对象的抽象是类,类的具体化(实例化)是对象 |
类的结构 | 客观世界中各类有结构一样,软件中类也有结构。一般有组合(平行)与聚合结构(部分构成主体) |
消息和方法 | 对象之间进行通信(交互)的信息称为消息,发送消息要指定接收的对象,对象中的执行方法名 |
三、面向对象的特征
基本概念 | 说明 |
---|---|
封装 | 封装就是在抽象出来的类中,将类对象具有的状态(属性)和行为(方法)放在同一个类中,避免外界任意修改类结构和数据,只向外提供修改内部私有数据的接口 |
继承 | 如果有几个类比较类似,就可以把这些类抽象出一个基类作为父类,子类共享父类的属性和方法,并可以增加新的属性和方法 |
多态 | 一条消息发送到不同的对象,不同的对象产生了不同的结果【如消息传播机制】 |
四、面向对象的要素
基本概念 | 说明 |
---|---|
抽象 | 先根据已有的对象分类,抽象出有哪些类,根据具有贤属性和方法的类去造对象 |
封装性(信息隐藏) | 封装是保证软件有良好模块性的基础,封装降低了对象之间的依赖,使得模块更加清晰 |
共享性 | 类的封装体现了对象的共享类的信息,继承体现了子类对父类的信息共享,多态体现了不同对象对消息的共享 |
强调对象结构而非程序结构 | 以对象及对象建的关系建立整个程序的结构 |
五、面向对象的开发方法
基本概念 | 说明 |
---|---|
基本概念 | 说明 |
---|---|
Booch方法 | 最先提出软件开发方法问题,指出面向对象的软件设计不同于传统的功能分解,在于对现实世界的抽象,并将其映射在软件中 |
Coad方法 | 进一步体现了类和类层次结构的认定 |
OMT方法 | “面对对象的建模与设计” |
UML(Unified Modeling Language)语言 | 最重要的成果之一就是统一建模语言(UML)的出现,UML是面向对象技术领域占主导地位的标准化建模语言 |
六、面向对象的模型
1、对象模型
对象模型描述了系统的静态结构,从客观世界对象的关系角度出发,描述在系统中对象之间的关系。主要关心对象的结构、属性、操作,是其他模型的基础。
基本概念 | 说明 |
---|---|
对象和类 | (1)对象:对象建模的目的就是描述对象。(2)类:类是对象的抽象,表示了同一类对象。抽象过程增加了模型的归纳能力。(3)属性指对象具有的属性状态值。(4)操作和方法:操作是对象能够实现的动作或行为。方法是抽象类的时候对对象动作的抽象。 |
关联和链 | 关联是类之间的联系,链是对象之间的联系。角色说明类在关联中的功能。受限关联对类之间的关联进行条件限制。关联的多重性通常描述为一或多 |
类的层次结构 | (1)聚集关系是一种整体-部分的关系。(2)一般化关系主要指基类和子类的继承关系。 |
对象模型 | (1)模板:模板是类、关联、一般化结构的逻辑组成。(2)对象模型是由一个或多个模板组成 |
2、动态模型
动态模型描述系统中控制的过程,或者执行的顺序。即数据的转换状态。
基本概念 | 说明 |
---|---|
事件 | 特定时刻发生的某件事 |
状态 | 对象的属性响应事件,到了某一个状态值 |
状态图 | 状态图是一个标准的计算机概念。是有限自动机的图形表示。这里把状态图作为建立动态模型的图形工具。状态图是一种图,用结点表示状态,结点用圆圈表示;圆圈内有状态名,用箭头连线表示状态的转换,上面标记事件名,箭头方向表示转换的方向。 |
3、功能模型
功能模型描述了系统中的计算,即系统由哪些功能组成。即数据的状态转换进行了哪些转换的计算。
功能模型由数张数据流图组成,数据流图由对象、处理、数据流组成。
基本概念 | 说明 |
---|---|
动作 对象 | 即对哪个对象要进行函数处理的对象,或者调用函数的对象 |
处理 | 功能转换,一般以函数(方法)体现,可以对数值进行改变 |
数据流 | 用数据流来表示数据转换的过程 |
数据存储对象 | 负责存储最终计算结果数据的对象,一般是存储模块 |
七、面向对象的分析
面向对象分析的目的是对客观世界系统进行建模。本节以面向对象的模型(对象模型、动态模型、功能模型)为基础,结合“银行网络系统”的具体实例来构建客观世界系统的对应模型。
分析建模的用途:
- 用来明确用户需求
- 为用户和开发人员提供明确的需求
- 为用户和开发人员提供一个协商的基础,作为后续的设计和实现的框架。
(一)、面向对象的分析
面向对象对系统进行分析的第一步是:陈述需求。需要用户和分析需求者一起完成希求分析,这样才能保证需求不偏离用户的真实意图。
银行网络系统问题陈述:设计支持银行网络的软件,银行网络包括人工出纳站和分行共享的自动出纳机。每个分理处用分理处计算机来保存各自的帐户,处理各自的事务;各自分理处的出纳站与分理处计算机通信,出纳站录入帐户和事务数据;自动出纳机与分行计算机通信,分行计算机与拨款分理处结帐,自动出纳机与用户接口接受现金卡,与分行计算机通信完成事务,发放现金,打印收据;系统需要记录保管和安全措施;系统必须正确处理同一帐户的并发访问;每个分处理为自己的计算机准备软件,银行网络费用根据顾客和现金卡的数目分摊给各分理处。
(二)、建立对象模型
确定对象和关联。然后确定对象的属性,分类需要哪些类,确定类的属性、方法,类与类之间的交互。最后确定整个对象模型。
1、确定类
构造对象模型的第一步是提出问题领域内的所有对象类,对象可能是实体,也有可能是概念。所有类都应在系统中有意义,有些类是明显的,有些类是隐藏在信息中的。
查找问题中所有的名词,产生如下的暂定类:
软件 银行网络 出纳员 自动出纳机 分行
分处理 分处理计算机 帐户 事务 出纳站
事务数据 分行计算机 现金卡 用户 现金
收据 系统 顾客 费用 帐户数据
访问 安全措施 记录保管
根据下列标准,去掉不必要和不准确的类:
基本概念 | 说明 |
---|---|
冗余类 | 若两个类表示同一个信息,保留最富有描述能力的那个类。例如用户和顾客,保留顾客类。 |
不相关的类 | 除掉与问题没有关联性的类,例如“摊派费用”。 |
模糊类 | 类必须是确定的,有些类没有边界,如“记录保管”就是模糊类,它是事务中的。 |
去掉属性 | 某些名词是其他对象的属性,去掉。 |
去掉操作 | 如果名词有动作含义,就可能是动作,从类名词中去掉。 |
在银行网络系统中,模糊类是"系统"、"安全措施"、"记录保管"、"银行网络"等。属于属性的有:"帐户数据"、"收据"、"现金"、"事务数据"。属于实现的如:"访问"、"软件"等。这些均应除去。
2、准备数据字典
为所有确定的类建立数据字典,包括对类、类成员属性、方法的详细描述。
3、确定关联
两个或多个类之间的相互依赖就是关联。
关联常用描述性动词或动词词组来表示,其中有物理位置的表示、传导的动作、通信、所有者关系、条件的满足等。从问题陈述中抽取所有可能的关联表述,把它们记下来,但不要过早去细化这些表述。
下面是银行网络系统中所有可能的关联,大多数是直接抽取问题中的动词词组而得到的。在陈述中,有些动词词组表述的关联是不明显的。最后,还有一些关联与客观世界或人的假设有关,必须同用户一起核实这种关联,因为这种关联在问题陈述中找不到。
银行网络问题陈述中的关联:
- 银行网络包括出纳站和自动出纳机;
- 分行共享自动出纳机;
- 分理处提供分理处计算机;
- 分理处计算机保存帐户;
- 分理处计算机处理帐户支付事务;
- 分理处拥有出纳站;
- 出纳站与分理处计算机通信;
- 出纳员为帐户录入事务;
- 自动出纳机接受现金卡;
- 自动出纳机与用户接口;
- 自动出纳机发放现金;
- 自动出纳机打印收据;
- 系统处理并发访问;
- 分理处提供软件;
- 费用分摊给分理处。
- 隐含的动词词组:
- 分行由分理处组成;
- 分理处拥有帐户;
- 分行拥有分行计算机;
- 系统提供记录保管;
- 系统提供安全;
- 顾客有现金卡。
基于问题域知识的关联
- 分理处雇佣出纳员;
- 现金卡访问帐户。
使用下列标准去掉不必要和不正确的关联:
(1) 若某个类已被删除,那么与它有关的关联也必须删除或者用其它类来重新表述。在例中,我们删除了"银行网络",相关的关联也要删除。
(2)不相干的关联或实现阶段的关联:删除所有问题域之外的关联或涉及实现结构中的关联。如"系统处理并发访问"就是一种实现的概念。
(3)动作:关联应该描述应用域的结构性质而不是瞬时事件,因此应删除"自动出纳机接受现金卡","自动出纳机与用户接口"等。
(4)派生关联:省略那些可以用其他关联来定义的关联。因为这种关联是冗余的。银行网络系统的初步对象图。其中含有关联。
4、确定属性
属性用来表述对象的性质,通常是名词,但依赖与对象。
属性不一定全部在问题描述中,首先要找到重要属性。
按下列标准删除不必要的和不正确的属性:
(1) 对象:若实体的独立存在比它的值重要,那么这个实体不是属性而是对象。如在邮政目录中,"城市"是一个属性,然而在人口普查中,"城市"则被看作是对象。在具体应用中,具有自身性质的实体一定是对象。
(2) 定词:若属性值取决于某种具体上下文,则可考虑把该属性重新表述为一个限定词。
(3) 名称:名称常常作为限定词而不是对象的属性,当名称不依赖于上下文关系时,名称即为一个对象属性,尤其是它不惟一时。
(4)标识符:在考虑对象模糊性时,引入对象标识符表示,在对象模型中不列出这些对象标识符,它是隐含在对象模型中,只列出存在于应用域的属性。
(5) 内部值:若属性描述了对外不透明的对象的内部状态,则应从对象模型中删除该属性。
(6) 细化:忽略那些不可能对大多数操作有影响的属性。
5、使用继承来细化类
使用继承来共享公共结构,可以来组织类。可以用两种方式进行用集成细化类:
(1)自底向上通过把现有类的共同性质一般化为父类,寻找具有相似的属性,关系或操作的类来发现继承。例如"远程事务"和"出纳事务"是类似的,可以一般化为" 事务"。有些一般化结构常常是基于客观世界边界的现有分类,只要可能,尽量使用现有概念。对称性常有助于发现某些丢失的类。
(2)自顶向下将现有的类细化为更具体的子类。具体化常常可以从应用域中明显看出来。应用域中各枚举字情况是最常见的具体化的来源。例如:菜单,可以有固定菜单,顶部菜单,弹出菜单,下拉菜单等,这就可以把菜单类具体细化为各种具体菜单的子类。当同一关联名出现多次且意义也相同时,应尽量具体化为相关联的类,例如"事务"从"出纳站"和"自动出纳机"进入,则"录入站"就是"出纳站"和"自动出纳站"的一般化。在类层次中,可以为具体的类分配属性和关联。各属性和都应分配给最一般的适合的类,有时也加上一些修正。
应用领域中各情况的枚举是最常见的类具体化来源。
6、完善对象模型
对象建模不可能一次就能保证模型是完全正确的,软件开发的整个过程就是一个不断完善的过程。模型的不同组成部分多半是在不同的阶段完成的,如果发现模型的缺陷,就必须返回到前期阶段去修改,有些细化工作是在动态模型和功能模型完成之后才开始进行的。
(1) 几种可能丢失对象的情况及解决办法:
·同一类中存在毫无关系的属性和操作,则分解这个类,使各部分相互关联;
·一般化体系不清楚,则可能分离扮演两种角色的类
·存在无目标类的操作,则找出并加上失去目标的类;
·存在名称及目的相同的冗余关联,则通过一般化创建丢失的父类,把关联组织在一起。
(2) 查找多余的类。
类中缺少属性,操作和关联,则可删除这个类。
(3) 查找丢失的关联。
丢失了操作的访问路径,则加入新的关联以回答查询。
(4) 网络系统的具体情况作如下的修改:
①现金卡有多个独立的特性。把它分解为两个对象:卡片权限和现金卡。
a.卡片权限:它是银行用来鉴别用户访问权限的卡片,表示一个或多个用户帐户的访问权限;各个卡片权限对象中可能具有好几个现金卡,每张都带有安全码,卡片码,它们附在现金卡上,表现银行的卡片权限。
b.现金卡:它是自动出纳机得到表示码的数据卡片,它也是银行代码和现金卡代码的数据载体。
②"事务"不能体现对帐户之间的传输描述的一般性,因它只涉及一个帐户,一般来说,在每个帐户中,一个"事务"包括一个或多个"更新",一个"更新"是对帐户的一个动作,它们是取款,存款,查询之一。一个"更新"中所有"更新"应该是一个原子操作。
③"分理处"和"分离处理机"之间,"分行"和"分行处理机"之间的区别似乎并不影响分析,计算机的通信处理实际上是实现的概念,将"分理处计算机"并入到"分理处",将"分行计算机"并入到"分行"。
(三)、建立动态模型
动态模型是在对象模型的基础上,构建对象之间的活动路线。
1、准备脚本
脚本:戏剧用语。脚本可以说是故事的发展大纲,用以确定故事的发展方向。之后,确定故事到底是在什么地点,什么时间,有哪些角色,角色的对白,动作,情绪的变化,等等。
先找到对象的所有事件,再确定事件的时间顺序。
2、确定事件
确定所有外部事件。事件包括所有来自或发往用户的信息、外部设备的信号、输入、转换和动作,可以发现正常事件,但不能遗漏条件和异常事件。
3、准备事件跟踪表
把脚本表示成一个事件跟踪表,即不同对象之间的事件排序表,对象为表中的列,给每个对象分配一个独立的列。
类似于泳道图
。
4、构造状态图
对各对象类建立状态图,反映对象接收和发送的事件,每个事件跟踪都对应于状态图中一条路径。
泳道图:各个对象的事件,以及事件的时间顺序。
(四)、建立功能模型
目的:建立数据流图
。
功能模型用来说明值的转换,以及数据的流动。表明值之间的依赖关系以及实现的功能。
数据流图有助于表示数值之间的依赖关系。变量、属性等是虚体,但是数值是实体。
功能模型中的数值处理对应于状态图中的活动和动作,数据流对应于对象图中的对象或属性。
状态图:
1、确定输入值、输出值
先列出输入值、输出值,输入输出是外界动作与系统之间事件的参数。
2、建立数据流图
数据流图说明从输入值到输出值的转换过程。数据流图通常按层次组织。
一个数据流图:
(五)、确定操作
在建立对象模型时,确定了类、关联、结构和属性,还没有确定操作。只有建立了动态模型和功能模型之后,才可能最后确定类的操作。
即最后确定各个类中对象的操作,也就是确定方法或函数
中的内容。
八、面向对象的设计
面向对象设计是把分析阶段的需求和模型转化成符合质量、符合要求的抽象系统方案
的过程。
从面向对象分析到面向对象设计是一个逐渐扩充模型的过程。
瀑布模型
把设计进一步划分成(1)概要设计和(2)详细设计两个阶段,类似地,也可以把面向对象设计再细分为系统设计
和对象设计
。
- 系统设计:确定实现系统的策略和目标系统的高层结构。(对应概要设计)
- 对象设计:确定解空间中的类、关联、接口形式及实现操作的算法。(对应详细设计)
(一)、面向对象设计的原则
1、模块化
面向对象开发方法很自然地支持了把系统分解成模块的设计原则:对象就是模块。(类就是模块)
它是把数据结构和操作这些数据的方法紧密地结合在一起所构成的模块。
2、抽象
面向对象方法不仅支持过程抽象,而且支持数据抽象。
3、信息隐藏
在面向对象方法中,信息隐藏通过对象的封装性来实现。
4、低耦合
在面向对象方法中,对象是最基本的模块,因此,耦合主要指不同对象之间相互关联的紧密程度。低耦合是设计的一个重要标准,因为这有助于使得系统中某一部分的变化对其它部分的影响降到最低程度。
即降低模块之间的依赖程度。
5、高内聚
- (1)操作内聚。
- (2)类内聚。
- (3)一般——具体内聚。
即模块内部要尽量紧凑,集合度高。
(二)、面向对象设计的启发规则
1、设计结果应该清晰易懂
使设计结果清晰、易懂、易读是提高软件可维护性和可重用性的重要措施。显然,人们不会重用那些他们不理解的设计。
要做到:
- (1)用词一致。
- (2)使用已有的协议。
- (3)减少消息模式的数量。
- (4)避免模糊的定义。
2、一般类和具体类的深度应该适当
即继承或抽象的链要适度。
3、设计的类尽量简单
应该尽量设计小而简单的类,这样便以开发和管理。为了保持简单,应注意以下几点:
- (1)避免包含过多的属性。
- (2)有明确的定义。
- (3)尽量简化对象之间的合作关系。
- (4)不要提供太多的操作。
4、使用简单的协议
一般来说,消息中参数不要超过3个。(限制消息中传递的信息个数)
5、使用简单的操作
面向对象设计出来的类中的操作通常都很小,一般只有3至5行源程序语句,可以用仅含一个动词和一个宾语的简单句子描述它的功能。
即函数不要太长。
6、把设计变动减到最小
通常,设计的质量越高,设计结果保持不变的时间也越长。即使出现必须修改设计的情况,也应该使修改的范围尽可能小。
(三)、面向对象设计的系统设计
系统设计是问题求解及建立解答的高级策略。必须制定解决问题的基本方法,系统的高层结构形式包括子系统的分解、它的固有并发性、子系统分配给硬软件、数据存储管理、资源协调、软件控制实现、人机交互接口。
1、系统设计概述
设计阶段先从高层入手,然后细化。系统设计要决定整个结构及风格,这种结构为后面设计阶段的更详细策略的设计提供了基础。
系统设计的步骤为:
设计 | 描述 |
---|---|
1.系统分解 | 系统中主要的组成部分称为子系统,子系统既不是一个对象也不是一个功能,而是类、关联、操作、事件和约束的集合。 |
2.确定并发性 | 分析模型、现实世界及硬件中不少对象均是并发的。 |
3.处理器及任务分配 | 各并发子系统必须分配给单个硬件单元,要么是一个一般的处理器,要么是一个具体的功能单元。 |
4.数据存储管理 | 系统中的内部数据和外部数据的存储管理是一项重要的任务。通常各数据存储可以将数据结构、文件、数据库组合在一起,不同数据存储要在费用、访问时间、容量及可靠性之间做出折衷考虑。 |
5.全局资源的处理 | 必须确定全局资源,并且制定访问全局资源的策略。 |
6.选择软件控制机制 | 分析模型中所有交互行为都表示为对象之间的事件。系统设计必须从多种方法中选择某种方法来实现软件的控制。 |
7.人机交互接口设计 | 设计中的大部分工作都与稳定的状态行为有关,但必须考虑用户使用系统的交互接口。 |
2、确定系统的一般框架
3、系统分解,建立系统结构
可用的软件库以及程序员的编程经验。
通过面向对象分析得到的问题域精确模型,为设计体系结构奠定了良好的基础,建立了完整的框架。(分解实现各部分框架)
4、选择软件控制机制
软件系统中存在两种控制流,外部控制流和内部控制流。(确定外部控制线、内部控制线)
5、数据存储管理
数据存储管理是系统存储或检索对象的基本设施,它建立在某种数据存储管理系统之上,并且隔离了数据存储管理模式的影响。(DB设计)
6、设计人机交互接口
在面向对象分析过程中,已经对用户界面需求作了初步分析,在面向对象设计过程中,则应该对系统的人机交互接口进行详细设计,以确定人机交互的细节,其中包括指定窗口和报表的形式、设计命令层次等项内容。(HMI设计)
(四)、面向对象设计的对象设计
1、对象设计概述
2、将对象模型、动态模型、功能模型结合
- (1)获得操作。
- (2)确定操作的目标对象。
3、算法设计
对象操作设计,即确定函数(方法)中的具体算法。
4、优化设计
设计完成以后对应整个系统分析是否合理,并进行修改。
5、控制的实现
分析所有对象的事件,确定要演绎的脚本,即确定事件发生的时间顺序。
6、调整继承
抽象一般化的操作,列举同类的对象,从一般化的模板实现继承,降低冗余度。
7、关联的设计
各个类(对象)之间关联的设计。
九、面向对象的实现
(一)、程序设计语言
采用面向对象方法开发软件的基本目的和主要优点是通过重用提高软件的生产率。因此,应该优先选用能够最完善、最准确地表达问题域语义的面向对象语言。
在选择编程语言时,应该考虑的其他因素还有:对用户学习面向对象分析、设计和编码技术所能提供的培训操作;在使用这个面向对象语言期间能提供的技术支持;能提供给开发人员使用的开发工具、开发平台,对机器性能和内存的需求,集成已有软件的容易程度。
(二)、类的实现
- (1)提高重用性。
- (2)提高可扩充性。
- (3)提高健壮性。
在开发过程中,类的实现是核心问题。在用面向对象风格所写的系统中,所有的数据都被封装在类的实例中。而整个程序则被封装在一个更高级的类中。在使用既存部件的面向对象系统中,可以只花费少量时间和工作量来实现软件。只要增加类的实例,开发少量的新类和实现各个对象之间互相通信的操作,就能建立需要的软件。
一种方案是先开发一个比较小、比较简单的来,作为开发比较大、比较复杂的类的基础。
- (1)“原封不动”重用。
- (2)进化性重用。
一个能够完全符合要求特性的类可能并不存在。
- (3)“废弃性”开发。
不用任何重用来开发一个新类。
- (4)错误处理。
一个类应是自主的,有责任定位和报告错误。
(三)、应用系统的实现
应用系统的实现是在所有的类都被实现之后的事。实现一个系统是一个比用过程性方法更简单、更简短的过程。有些实例将在其他类的初始化过程中使用。而其余的则必须用某种主过程显式地加以说明,或者当作系统最高层的类的表示的一部分。
在C++和C中有一个main( )函数,可以使用这个过程来说明构成系统主要对象的那些类的实例。
整个系统的控制类应该处于更高的层次,并且简单、简短。
(四)、面向对象测试
- (1)算法层。
- (2)类层。
测试封装在同一个类中的所有方法和属性之间的相互作用。
- (3)模板层。
测试一组协同工作的类之间的相互作用。
- (4)系统层。
把各个子系统组装成完整的面向对象软件系统,在组装过程中同时进行测试。
十、面向对象和基于对象的区别
很多人没有区分“面向对象”和“基于对象”两个不同的概念。面向对象的三大特点(封装,继承,多态)缺一不可。通常“基于对象”是使用对象,但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说“基于对象”没有继承的特点。而“多态”表示为父类类型的子类对象实例,没有了继承的概念也就无从谈论“多态”。很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。“面向对象”和“基于对象” 都实现了“封装”的概念,但是面向对象实现了“继承和多态”,而“基于对象”没有实现这些,的确很饶口。
从事面向对象编程的人按照分工来说,可以分为“类库的创建者”和“类库的使用者”。使用类库的人并不都是具备了面向对象思想的人,通常知道如何继承和派生新对象就可以使用类库了,然而我们的思维并没有真正的转过来,使用类库只是在形式上是面向对象,而实质上只是库函数的一种扩展。
面向对象是一种思想,是我们考虑事情的方法,通常表现为我们是将问题的解决按照过程方式来解决呢,还是将问题抽象为一个对象来解决它。很多情况下,我们会不知不觉的按照过程方式来解决它,而不是考虑将要解决问题抽象为对象去解决它。有些人打着面向对象的幌子,干着过程编程的勾当。
总结
以生产一只鸭子对象为例:
1、鸭子抽象类
要有一只鸭子,就首先要有一只鸭子类。鸭子可能有很多类,所以抽象出一个鸭子抽象类。所有的鸭子类都可以通过继承鸭子抽象类产生一个特定种类的鸭子类。
abstract class Duck
{
public IFlyBehavior flyBehavior;
public IQuackBehavior quackBehavior;
public Duck()
{
}
public abstract void display();
public void performFly()
{
flyBehavior.fly();
}
public void performQuack()
{
quackBehavior.quack();
}
public void swim()
{
Console.WriteLine("All ducks float, even decoys!");
}
}
2、鸭子类
通过继承鸭子抽象类,产生一个特定的鸭子类。继承父类的所有属性与方法,也可产生新的属性和方法。
class ModelDuck : Duck
{
public ModelDuck()
{
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
public override void display()
{
Console.WriteLine("I'm a ModelDuck!\n");
}
}
3、鸭子动作的抽象接口
鸭子可能有飞的动作,叫的动作,飞和叫可能有不同的形式。将飞和叫这两种动作分别抽象出接口类,其中有动作接口函数。
interface IFlyBehavior
{
void fly();
}
interface IQuackBehavior
{
void quack();
}
4、不同的飞和不同的叫的实现
public class FlyWithWinds : IFlyBehavior
{
public void fly()
{
Console.WriteLine("I'm flying!\n");
}
}
public class FlyNoWay : IFlyBehavior
{
public void fly()
{
Console.WriteLine("I can't flying!\n");
}
}
public class Quack : IQuackBehavior
{
public void quack()
{
Console.WriteLine("Quack!\n");
}
}
public class MuteQuack : IQuackBehavior
{
public void quack()
{
Console.WriteLine("<< Silence >>\n");
}
}
public class Squeak : IQuackBehavior
{
public void quack()
{
Console.WriteLine("Squeak!\n");
}
}
5、运行效果
6、完整代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 鸭子模式
{
class Program
{
static void Main(string[] args)
{
Duck ModelDuck1 = new ModelDuck();
ModelDuck1.performFly();
ModelDuck1.performQuack();
ModelDuck1.display();
Console.ReadLine();
}
}
class ModelDuck : Duck
{
public ModelDuck()
{
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
public override void display()
{
Console.WriteLine("I'm a ModelDuck!\n");
}
}
abstract class Duck
{
public IFlyBehavior flyBehavior;
public IQuackBehavior quackBehavior;
public Duck()
{
}
public abstract void display();
public void performFly()
{
flyBehavior.fly();
}
public void performQuack()
{
quackBehavior.quack();
}
public void swim()
{
Console.WriteLine("All ducks float, even decoys!");
}
}
interface IFlyBehavior
{
void fly();
}
public class FlyWithWinds : IFlyBehavior
{
public void fly()
{
Console.WriteLine("I'm flying!\n");
}
}
public class FlyNoWay : IFlyBehavior
{
public void fly()
{
Console.WriteLine("I can't flying!\n");
}
}
interface IQuackBehavior
{
void quack();
}
public class Quack : IQuackBehavior
{
public void quack()
{
Console.WriteLine("Quack!\n");
}
}
public class MuteQuack : IQuackBehavior
{
public void quack()
{
Console.WriteLine("<< Silence >>\n");
}
}
public class Squeak : IQuackBehavior
{
public void quack()
{
Console.WriteLine("Squeak!\n");
}
}
}