当前课程知识点:面向对象分析与设计 > 类设计 > 定义类的泛化关系、解决用例冲突、非功能性需求 > 定义类的泛化关系、解决用例冲突、非功能性需求
同学们今天我们讲面向对象分析与设计这门课的第25课类设计四
在这讲里面 我们首先介绍类的泛化关系设计
什么是泛化关系呢 是指的一个类可以共享一个或者多个类的结构和行为
泛化关系是一种is a kind of关系
比如说是一种子类关系
比如我们在这个例子里面
我们可以看到对于银行账户来讲
支票和存款都是银行帐户的一种
所以支票存款和银行账户之间就是一种泛化关系
同样的在这页ppt里面狮子是动物的一种
老虎也是动物的一种 所以狮子和老虎都属于动物的一种
他们和动物这个类之间就有泛化关系
在泛化关系里面我们一般把基类定义成一个抽象类
而把子类定义成具体类 这样的话每个子类可以有他具体的实例
基类作为抽象类的他不允许创建他的实例
看下面这个图 我们说鸟是一种动物
所以鸟和动物之间建立的一种泛化关系
同样鸟又是一种飞行物 所以鸟和飞行器之间也建立了一种泛化关系
我们把一个类它有两个基类的这种关系呢
我们称之为多重继承
但是呢多重继承可能会带来很多问题
首先在鸟里面他可能会继承两个对象 分别是从动物继承一个基类对象
然后从飞行事务里面继承一个基类对象
这两个继承对象里面都有属性color颜色
这样的话她就继承了两个color这样一个属性
在后面使用的时候可能就会引起冲突
另外一种情况下动物和这个飞行事物他们又去公共继承了一个基类某个类
那么在这种多重继承的情况下呢
这个公共的这个基类他可能在这个鸟里边被重复继承了两次
也同样会引发一些错误和问题
在泛化关系里边我们可以定一泛化约束方法
约束主要有四种完全的非完全的
完全的则描述了整个泛化关系的继承树是完整的
不允许再给他定义新的子类
而非完全的我们可以给继承树里边儿再来扩展新的子类
再下来是Disjoint分离的意味着子类不允许多重继承
而overlapping不重叠的则可以允许子类进行多重继承
在这个例子里面我们的银行资产他是disjoint
他下面的三个子类银行账户不动产和投资
不允许再往下定义子类多重继承上面这些子类
那么对于银行账户来讲他定义的约束是Disjoint和Complete
比如说分离的和完全的那么银行账户下边只能有
这两个子类存款和这个银行账户和支票 不允许再增加新的子类
在这张图里面我们可以看到
上面是一个车辆 车辆他又分为两个子类分别是陆地的和这个水上
他们的约束关系是overlap的这样的话呢我们可以再定义一个新的子类
这个子类可以同时多重继承分别继承这两个类
这是一个水陆两用车泛化关系和聚集关系之间很容易被混用被混淆
我们来区分一下我们说泛化关系
它是一种is a kind of这种关系
而聚集关系他描述的是一种整体部分关系也就是说is a part of这样一个关系
在下面这个例子里面我们可以看到我们定义了一个类
这个类呢是一个带滚动条的窗口
他同时继承了两个基类 一个是窗口这个类 一个是滚动条这种类
这种设计正确吗很明显这种设计是有问题的
我们说带有滚动条的窗口他是窗口的一种
所以他和窗口之间的泛化关系是正确的
但是带有滚动条的窗口他并不是滚动条的一种所以他和滚动条之间的泛化关系是错误的
而滚动条是带有滚动条窗口的一部分是真实的
他们之间的关系应该是一种组合关系
接下来我们来看一种比较特殊的
我们刚才讲呢左边的狮子是动物的一种老虎是动物一种
他们和动物之间泛化关系是正确的
那么右边这个上面是一个list数组下面是一个堆栈
那么堆栈来继承数组这种关系正确吗
很明显这种关系是有问题的
我们知道数组可以从任何位置进行插入和删除元素
而堆栈是有严格要求的 只能从堆栈的顶插入
从堆栈的底部取走或者删除元素
也就换句话讲堆栈并不是List的一种
但是我们又发现
对任何list 他们在这个操作上有很多相似的地方
我们希望对他进行复用复用他的实现
那如何来那个做到呢
我们有两种方式 第一种按传统方式我们定义堆栈和list的一个公共基类
我们把它叫线性容器 然后这个list和堆栈都去继承这个线性容器类
还有一种情况下
我们希望堆栈他能够使用list的内部实现
这种时候我们把这个list 建立和堆栈之间的一种组合关系
我们把对堆栈的操作可以委托给组合以后他所包含的类似的对象来完成
这种情况下我们的堆栈的实现就可以复用 list的代码或者说list的程序
我们把这种情况也称之为共享实现委托或者把他称之为实现继承
我们在继承关系里面呢加注标数是一种实现继承
那么在实现继承的情况下他就意味着
子类并不去复用或者说完全共享基类的行为和属性
他只是复用基类里边的程序实现
下面我们再介绍一个概念呢
称之为多态 什么是多态呢
就是同一个操作 在不同对象里面可能会有不同的实现和不同的行为
我们把他称之为多态
我们画了个例子这个例子里面呢下面是一个万能遥控器
他发出的遥控指令在不同的品牌的电视机里面
他可能会有不同的响应
那么这种情况下就称之为多态
引入多态的好处是什么呢在没有引入多态之前
我们在这个例子里面我们写程序的时候我们首先必须要判断一下当前这个对象
他真实的实例是一个狮子还是老虎
然后呢他在调用狮子和老虎的具体操作在引入多态以后
我们只需要给出这个基类实例的一个操作
就可以了那么在程序运行过程中
他会实际来判断当前这个动物如果是狮子他就会调狮子的操作
如果是老虎他就会调老虎的操作这样的话呢
他就可以实现多态
多态的实现方式呢可以除了这个继承关系以外
就是通过泛化以外也可以通过接口来实现
我们首先讲一下通过接口来实现这个多态的优点在什么地方
在接口实现多态的时候这种实现关系和他的继承关系是没有任何关系的
比如说他可以跨越继承关系或者这样讲实现同一个接口的两个类之间
不需要有任何的继承关系 只要他们实现了同一个接口
他们就可以实现多态 而且接口只定义纯粹的行为规约
接口并不提供缺省的这个行为是如何来实现的
在这点上 接口和这个抽象类有相似的地方
但是抽象类呢除了定义行为规约以外
还可以定义一些缺省的属性接口呢是完全和实现独立的
他和集成是没有任何关系的而泛化是可以对这个实现的进行复用的
而接口呢只能用来对它的行为规约比如说操作的定义呢进行复用
泛化和接口呢都提供了这种对多态的实现方式
在泛化模式下我们如何来定义他的基类呢
如果在基类里面只需要提供接口
我们就可以把基类定义成一个抽象类
同时呢 在这个子类里边定义抽象类里边所定义的操作是如何来具体实现的
第二种情况下我们可能需要给出在基类里边定义所有子类的缺省时限
这种情况下我们需要把基类定义成一个具体类
来给出操作的实现方法
但是我们允许在子类里边对实现方法进行重写
从而实现和支持多态操作
第三种情况下,我们希望在子类里边实现基类的强制行为
同样我们需要把基类定义成一个具体类给出它操作的实现
然后不允许在子类里边对这个操作进行重写 不允许进行多态
下面我们看一个新的概念 叫变异
什么是变异是指的一个类的对象
它在形状 结构 行为 功能规约上有着显著的变化
我们把它称之为变异
在生活中最常见的变异就是蝌蚪变青蛙
我们知道蝌蚪最开始跟像鱼一样的
等变成青蛙的时候
它就长出了四条腿
能跳了
这种变化我们就称之为变异
变异是现世界中存在的
所以我们作为面向对象的软件编程
我们需要有方法能够支持或者说实现这种变异的设计和实现
我们在教学系统里边也同样有变异的问题
我们这里看一个例子
在学校里边有两类学生
一类是全日制学生
一类是非全日制学生
那么非全日制学生可能在选课的时候
最多一次只能选三门课程
但是全日制没有最多课程选课数量的限制
另外全日制学生必须要求在两年的时间毕业
而非全日制的学生就没有这方面的要求
所以在设计的时候
我们可以分别定义全市学生内和非全日制学生类
当然了全日制学生和非全日制学生有很多公共的
属性和操作
所以我们可以首先第一个基类词语student
然后定义这两个类和基类之间的泛化关系
但是这样一种设计的情况下
当某个学生他入学的时候是非全日制学生
在入学阶段
它通过了考试或者选拔要转换成全日制学生
我们又该如何来实现
很显然在前面的设计模式下我们是无法实现的
我们只能把它作为一个非全日制的学生对象
删掉
重新给他创建一个全日制学生对象
这样的话在设计的时候它是两个对象
而现实生活中它是同一个同学
是同一个学生
所以这种设计很明显是存在问题的
如何来改定
我们可以通过第二种方式
我们还是在定义学生类
在学生这个类里边
我们组合了一个新的类这个类的
我们把它称之为学生类型
然后学生类型后面我们又定义了两种
一种是全日制学生类型和非全日制学生类型
他们和学生类型类之间都具有这种泛化关系
通过这样一个设计
我们在创建一个学生的时候
我们刚开始学生的学生类型
我们可以把它设计非全日制
当需要变更为全日制的时候
由学生管理员发布消息给学生
这个对象把它的类型转换成全日制的
那么学生这个类首先删除掉之前的非全日制类型的对象
然后会创建一个新的全日制类型的对象
这样的话
这个学生他的身份就会从非全日制的学生转换为全日制的学生
也就说实现了我们这种变异的设计
那么变异设计
它提供了系统设计的一种灵活性
可以很好地解决这种变异问题
在设计完成以后
我们的用例设计
我们说它是迭代的
每一个用例我们要进行独立的用例设计
然后设计定义
识别它的设计类
识别它的子系统识别接口
然后完成子系统设计完成类的设计
在完成完以后
我们要和之前的设计要进行合并
然后我们可能会发现里边存在一些冲突
特别是可能里边还会存在一些并发冲突
如何来解决并发冲突
可能需要采用一些操作系统
或者说软件环境提供的一些支撑支持机制
那么第一种
比如说同步消息队列
通过同步消息队列实现对消息的先进先出的处理
第二种对于可能的并发操作或者代码进行并发保护
第三种运用一些并发机制像信号量 加锁 消息队列
通过这样一些使得对并发冲突这种错误得以避免和解决
当然并发问题最终要依赖于我们的实践环境
当然主要就是我们操作系统所能够支撑和提供的这样一些并发机制
另外的话我们还要处理在类设计里边的一些非功能性需求
这些非功能性需求可能就是我们前面所识别
出来的一些分析机制里边所定义的
比如说像安全性分布式等等
我们要给出他们具体的一些是如何来实现的
最后我们要检查我们类设计的正确性
好了 同学们
在这节课我们就介绍完类设计里边的泛化设计
用例冲突和非功能性需求问题
我们就和之前的类设计的三节课共同完成了
讲解了类设计的全部
类程也讲解完成了我们整门课程
谢谢大家
-软件开发过程中的主要问题和好的解决方法
--软件开发过程中的主要问题和好的解决方法
-RUP软件开发模型的特点
--RUP软件开发模型的特点
-四个基本原则
--四个基本原则
--四个基本原则
-对象和类
--对象和类
--对象和类
-类之间的关系
--类之间的关系
--类之间的关系
-用例模型
--用例模型
--用例模型
-用例之间的关系
--用例之间的关系
--用例之间的关系
-用例建模
--用例建模
--用例建模
-分析与设计概述
--分析与设计概述
--分析与设计概述
-架构分析基本概念
--架构分析基本概念
--架构分析基本概念
-定义模型的高层组织结构
--定义模型的高层组织结构
-确定分析机制、确定关键概念、创建用例实现
--确定分析机制、确定关键概念、创建用例实现
-用例分析概述
--用例分析概述
--用例分析概述作业
-控制类
--控制类
--控制类
-用例行为和类的关系
--用例行为与类的关系
-识别设计元素概述
--识别设计元素概述
--识别设计元素概述
-识别子系统及接口
--识别子系统和接口
--识别子系统及接口
-描述运行态软件体系架构
--描述运行态软件体系架构
-描述分布式系统架构概述
--描述分布式系统架构概述
-用例设计描述
--用例设计描述
--用例设计描述
-子系统设计概述
--子系统设计概述
--子系统设计概述
-创建初始设计类、定义类操作方法
--创建初始设计类、定义类操作方法
-定义类状态
--定义类状态
--定义类状态
-定义类之间的依赖关系、关联关系以及多重性设计
--定义类之间的依赖关系、关联关系以及多重性设计
-定义类的泛化关系、解决用例冲突、非功能性需求
--定义类的泛化关系、解决用例冲突、非功能性需求