OOSE-2-类图与软件设计/面向对象设计


1 类图

类图用来对面向对象的对象模型进行建模,对象模型用于表示静态的、结构化的系统的“数据”性质与模拟客观世界实体对象及其之间的联系,通常使用统一建模语言(Unified Modeling Language,UML)提供的类图来建立对象模型。

绘图工具可使用Visio,Visio是一款便于对复杂信息、系统和流程进行可视化处理、分析和交流的绘图软件。类的基本内容有:类名、属性与操作(或称为服务)。下面是一个示例:
在这里插入图片描述
在上图中:

1、+表示public;

2、#表示protected;

3、-表示private;

除此之外,属性定义格式如下:

[visibility]name[:type][=defautValue]

操作定义格式如下:

[visibility]name[(parameter-list)][:return-type-expression][{property string}]

下面是类在不同层次上的说明的一个例子:
在这里插入图片描述
类与类之间的关系有:关联、泛化(即继承)、依赖、细化(即实现)。

下面详细介绍这4种关系。

1.1 关联

关联描述的是两个类的对象之间存在着某种语义上的联系。

1.1.1 普通关联

普通关联是最常见的关联关系,只要在类与类之间存在着连接关系就可以用普通关联表示。符号表示是一条直线:
在这里插入图片描述
关联方向表示(有两个)是:▶和◀。此外有时还需要有关联的重数,即关联可以通过多重性来修饰,如下:

表示解释
1精确1个
*数目不限(0个或多个)
0…*0个或多个
1…*1个或多个
0…10个或1个
3…7指定范围(3-7,包含3、7)

示例如下:
在这里插入图片描述
关联的角色即参与此关联对象所扮演的角色,注意显式标明角色有助于理解,默认用类名作为角色名。下面是递归关联(指一个类与它本身有关联)的一个示例:
在这里插入图片描述
关联的每一个端点上都有一个角色,且每一个角色都具有一个名字,用来描述此类被其他的类看作是什么——将其称为角色名。需要强调的是,一个类在一个关联中拥有确切含义时,使用关联角色名。下面是一个示例:
在这里插入图片描述

1.1.2 限定关联

限定关联用在一对多或多对多的关联关系中,其作用是可把模型中的重数从一对多变成一对一,或把多对多简化为多对一。使用的符号如下示例:
在这里插入图片描述
本来目录中有多个文件,本来是一对多的关系,而上图列出了文件名,此时由于一个文件名对应一个文件,因此变成了一对一的关系。

1.1.3 关联类

关联本身也有特性,因此引入关联类,用于记录说明关联的附加信息,关联类是一种具有关联特性类特性的建模元素,其表示符号为虚线:
在这里插入图片描述
下面是一个示例:
在这里插入图片描述
带有属性和操作的关联表示为关联类。比如在教师和学生两个类中,有些属性是共有的,例如指导论文,使用关联类后如下:
在这里插入图片描述

1.1.4 聚集关联

聚集表示类与类之间是整体与部分的关系,分为聚合与组合。

1.1.4.1 聚合

聚合关系表示整体和部分可以分开。其符号表示是:
在这里插入图片描述
下面是一个示例:
在这里插入图片描述
下面是示例2:
在这里插入图片描述
一所大学由多个学院组成,它们体现的是一种整体与部分的关系,且整体和部分可以分开。

1.1.4.2 组合

组合关系表示整体和部分不可以分开,不要和聚合搞混。其符号表示是:
在这里插入图片描述
下面是一个示例:
在这里插入图片描述
下面是示例2:
在这里插入图片描述

1.2 泛化

泛化(generalization)描述的是特殊与一般的关系。其符号表示是:
在这里插入图片描述
下面是一个示例:
在这里插入图片描述
下面是示例2:
在这里插入图片描述
抽象类是没有具体对象的类,用于描述它的子类的公共属性和行为,在图中需要在类名的下方附加一个标记值:{abstract}。下面是一个示例:
在这里插入图片描述

1.3 依赖

依赖描述的是两个类之间的语义连接存在使用关系,它说明一个事物的规格说明变化可能影响到使用它的另一个事物。其符号表示是:
在这里插入图片描述
类的依赖可能由各种原因引起,如:

1、一个类向另一个类发送消息;

2、一个类是另一个类的数据成员;

3、一个类是另一个类的某个操作参数。

下面是一个示例:
在这里插入图片描述
下面是示例2:
在这里插入图片描述

1.4 细化

细化就是实现(realization),即同一个事物在不同抽象层次上的描述。符号表示如下:
在这里插入图片描述
下面是一个简单的示例:
在这里插入图片描述

1.5 案例分析

根据以下描述,画出相应的UML类图:

1、神舟六号飞船是神州飞船系列的一种,它由轨道舱、返回舱、推进舱和逃逸救生塔等组成。

2、航天员可以在返回舱内驾驶飞船,轨道舱是航天员工作和休息的场所。在紧急的情况下,航天员可利用逃逸救生塔逃生。

3、在飞船两侧有多个太阳能电池翼,可以为飞船提供电能。

分析如下:

1、泛化:神舟六号飞船是神州飞船系列的一种;聚合:它由轨道舱、返回舱、推进舱和逃逸救生塔等组成(因为整体和部分可以分开)。

2、依赖:航天员可以在返回舱内驾驶飞船;依赖:轨道舱是航天员工作和休息的场所;依赖:航天员可利用逃逸救生塔逃生。

3、关联:在飞船两侧有多个太阳能电池翼(不是聚合或者组合呢,对比第一个的“由…组成”可以看出)。

绘制的类图如下:
在这里插入图片描述


2 软件设计

2.1 软件设计的任务

软件设计的主要任务是回答怎么做。软件设计在软件开发中的重要性如下:

1、软件设计是软件生命周期中最重要的步骤,它是软件开发过程中质量得以保证的关键。软件设计提供了软件的表示,使得软件的质量评价成为可能;

2、软件设计是将用户需求准确地转化成为最终软件产品的唯一途径;

3、软件设计是后续开发步骤及维护的工作基础。如果没有软件设计,就只能建立一个不稳健的系统,只要出现一些小的变动,就会使软件垮掉,而且难以进行软件测试。

将分析模型转化为软件设计的步骤包括:

1、数据设计:将E-R图中描述的对象和关系以及数据库词典中描述的详细数据内容转化为某种数据结构;

2、体系结构:设计定义软件系统各主要成分之间的关系;

3、接口设计:定义软件内部各成分之间的、软件与其它协同系统之间的、软件与用户之间的交互机制

4、过程设计:把结构成分转换成软件的过程性描述,然后根据这种过程性描述去编写源代码,在成功通过软件测试后,最终得到完整有效的软件。

如下图:
在这里插入图片描述
软件设计是将软件需求变成软件表示的过程。从工程的角度来看,软件设计分两步走:先做概要设计,再做详细设计。其中:

1、概要设计:将软件需求转化为数据结构和软件的体系结构,并建立接口;

2、详细设计:即过程设计,通过对结构表示进行细化,得到更加详细的数据结构和算法。

其中:

1、设计必须实现分析模型中描述的所有显式需求,必须满足用户希望的所有隐式需求;

2、设计必须是可读的、可理解的、使得将来易于编程、易于测试和易于维护的;

3、设计应从实现角度出发,给出与数据、功能或行为相关的软件全貌。

2.2 总体设计

2.2.1 原理

设计原理有:模块化、抽象、逐步求精、信息隐藏、局部化、模块独立等。

1、模块化。模块是由边界元素限定的相邻程序元素的序列,而且有一个总体标识符代表它。其中:

  • 边界元素:如Begin…End、{…}、面向对象方法中的对象和对象内的方法等;
  • 相邻程序元素:如数据说明、可执行的语言等;
  • 模块是构成程序的基本构件。

模块化把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,把这些模块集成起来构成一个整体,可以完成指定的功能,以满足用户的需求。下面是模块化和软件成本之间的关系图,表明了模块的规模要适中:
在这里插入图片描述
2、抽象。在现实世界中有这样一些事物,它们的状态或过程之间总存在着某些相似的方面,把这些相似的方面集中和概括起来,暂时忽略它们之间的差异,这就是抽象,只需要抽出事物的本质特性而暂时不考虑它们的细节。

3、逐步求精。为了集中精力解决主要问题而尽量推迟对问题细节的考虑,逐渐细化。Miller法则:一个人在任何时候都只能把注意力集中在7±2个知识块上。

4、信息隐藏。对于一个模块内部的信息(过程和数据),需要这样设计——对于不需要这些信息的模块来说,这些信息应该是不能被访问的。

5、局部化。把一些关系密切的软件元素物理地放得彼此靠近。信息隐藏和局部化有利于软件的维护。

6、模块独立。模块独立是模块化、抽象、信息隐藏和局部化四个概念的直接结果。开发具有独立功能而且和其他模型之间没有过多的相互作用的模块,就可以做到模块独立。通常希望设计这样的软件结构——使得每个模块完成一个相对独立的特定子功能,并且和其它模块之间的关系很简单。模块独立的优点是:易于开发、易于测试和维护。模块独立程度的两个定性度量标准是内聚与耦合。

2.2.1.1 内聚

内聚衡量一个模块内部各个元素彼此结合的紧密程度,可类比于凝聚力。内聚是信息隐藏和局部化概念的自然扩展,理想的内聚模块只做一件事情,应将更多的注意力集中到提高模块的内聚程度上。下面是三种程度的内聚:

1、低内聚

  • 偶然内聚:一个模块完成一组任务,这些任务彼此之间即使存在关系,关系也是很松散的。如果一组语句在多处出现,可以把这样的语句作为一个模块以节省内存;
  • 逻辑内聚:一个模块完成的任务在逻辑上属于相同或相似的一类;
  • 时间内聚:一个模块包含的任务必须在同一时间段内执行。例:模块完成各种初始化工作。

2、中内聚

  • 过程内聚:一个模块内的处理元素是相关的,而且必须以特定的次序执行。例:使用程序流程图确定的模块划分,得到的模块就属于该种;
  • 通信内聚:模块中的所有元素都使用同一个输入数据或产生同一个输出数据。

3、高内聚

  • 顺序内聚:一个模块内的处理元素和同一个功能密切相关,而且这些处理必须顺序执行,一个模块的输出作为下一个模块的输入;
  • 功能内聚:模块内部的所有处理元素属于一个整体,完成单一的功能。
2.2.1.2 耦合

耦合衡量不同模块之间彼此相互依赖的紧密程度。下面是几种耦合:

1、数据耦合:两个模块之间彼此通过参数交换信息,而且交换的仅仅是数据;

2、控制耦合:两个模块彼此间交换的信息包括控制信息;

3、特征耦合:把整个数据结构作为参数传递而被调用的模块只需使用其中一部分数据元素时;

4、公共耦合:两个或多个模块通过一个公共数据环境相互作用时,如全局变量、共享通信区;

5、内容耦合:如:一个模块访问了另一个模块内部的数据;一个模块不通过正常入口而转到另一个模块的内容,如goto语句;两个模块有一部分代码重叠;一个模块有多个入口(这表明该模块有多个功能)。

2.2.1.3 设计原则

设计的原则是:

1、尽量使用数据耦合;

2、少用控制耦合和特征耦合;

3、限制公共环境耦合的范围;

4、完全不使用内容耦合。

需要说明的是,没有必要精确确定内聚的级别,不要过于纠结这些概念。设计时力争做到高内聚,辨认并找到低内聚的模块,通过修改提高模块的内聚程度,并降低模块间的耦合程度,总结起来就是高内聚与松耦合

2.2.2 启发式规则

启发式规则的目的是帮助软件开发人员去改进软件设计,最终达到提高软件质量的目的。启发式规则如下:

1、改进软件结构,提高模块的独立性,努力做到高内聚、松耦合。

2、模块规模要适中,模块的规模不应过大,最好不超过60行语句。当模块包含的语句数超过30行以后,模块的可理解性迅速下降;

3、模块的深度、宽度、扇出和扇入都应适当。如下图:
在这里插入图片描述
其中:

(1)深度:软件层次结构中的层次数;

(2)宽度:软件结构中,同一层次上模块总数的最大值。宽度越大越复杂;

(3)扇出:一个模块直接控制(调用)的模块数目。经验表明,一个设计得好的典型系统的平均扇出通常是3或4,扇出的上限通常是5到9;

(4)扇入:该模块被多少个上级模块直接调用。

设计很好的软件结构通常有这些特征:顶层扇出比较高,中层扇出较少,底层模块应有高扇入。

4、模块的作用域应在其控制域之内,其中:

(1)模块的作用域:受该模块内一个判定影响的所有模块的集合;

(2)模块的控制域:模块本身以及所有直接或间接从属于它的模块的集合。

5、力争降低模块接口的复杂程度。例:下面是一元二次方程求根的两个方案(方案一属于特征耦合,方案二易理解):

  • 方案一:QUAD_ROOT(TBL,X);
  • 方案二:QUAD_ROOT(A,B,C,ROOT1,ROOT2)。

6、设计单入口、单出口的模块;

7、可以通过模块名预测模块的功能。

2.3 详细设计

1、结构化程序设计;

2、人机界面设计;


3 面向对象设计

面向对象,Object-Oriented,即OO。

面向对象设计,Object-Oriented Design,即OOD。

面向对象分析,Object-Oriented Analysis,即OOA。

OOA与OOD之间的界限十分模糊,OOA到OOD是一个多次反复迭代的过程。OO在概念和表示方法上的一致性保证了在各项开发活动之间的平滑过渡,使开发人员易于跟踪整个系统的开发过程,这是OO方法的一大优势。

3.1 OOD的准则

OOD的准则如下:

1、模块化

2、抽象:类是一种抽象数据类型,将规格、说明抽象化。关于参数化抽象的例子如C++的模板类,示例:比较两个整形或浮点型数据的大小,并计算出最大值和最小值,如下:
在这里插入图片描述
3、信息隐藏:即对象的封装。

4、松耦合:对象之间的耦合可分为两类:

  • 交互耦合:通过消息实现,应降低消息连接的复杂程度;
  • 继承耦合:有必要提高继承耦合。

5、高内聚:内聚指出了组件内的各个元素对完成一个定义明确的目的所做出的贡献程度。有三种内聚:

  • 服务内聚:一个类的方法内聚;
  • 类内聚;
  • 一般-特殊内聚。

6、可重用:尽量使用现有的类,设计新类时应考虑将来的可重用性。

7、易维护

3.2 启发式规则

1、设计结果应清晰易懂。如:

  • 用词一致;
  • 使用已有的协议;
  • 减少消息模式的数目;
  • 避免模糊的定义。

2、一般-特殊结构的深度应适当。在中等规模的系统中,类等级层次数应保持在7±2。

3、设计简单的类。如:

  • 避免包含过多的属性;
  • 有明确的定义;
  • 简化对象之间的合作关系;
  • 不要提供太多的服务。

4、使用简单的协议。消息中的参数不超过3个。

5、使用简单的服务。尽量只有3-5行代码。

6、把设计变动减至最小。

3.3 软件重用

软件重用的三个层次:

1、知识重用;

2、方法和标准的重用;

3、软件成分的重用。软件成分的重用级别:

  • 代码重用,如复制-粘贴、继承;
  • 设计结果重用;
  • 分析结果重用。

典型的可重用软件成分有:项目计划、成本估计、体系结构、需求模型和规格说明、设计、源代码、用户文档和技术文档、用户界面、数据、测试用例等。

可重用构件应具备的特点:模块独立性强、具有高度可塑性、接口清晰、简明、可靠。

类的重用方式有:

1、实例重用:对象的重用;使用几个类创建一个复杂类。

2、继承重用:对已有类的构件的可裁剪机制。

3、多态重用。

3.4 系统分解

OOD模型大体上由4个子系统构成,分别是:问题域子系统、人机交互子系统、任务管理子系统、数据管理子系统。影响OOD的因素有:

1、编程语言;

2、可用的构件库;

3、程序员的编程经验等。

3.4.1 问题域子系统

OOD的任务是:

1、仅需从实现角度对问题模型做一些补充或修改,主要是增添、合并或分解类与对象、属性及服务,调整继承关系等;

2、设计过程中,可能对OOA所得到的问题域模型进行补充或修改;

3、包括:

  • 调整需求,需要调整需求的情况是用户需求或外部环境发生了变化,或者分析员对问题域理解不透彻或缺乏领域专家帮助。
  • 重用已有的类,删去无用属性、添加泛化关系、调整或修改关联。
  • 把问题域类组合在一起,引入一个根类。
  • 增添一般化类以建立协议。
  • 调整继承层次,使用多继承或单继承。

3.4.2 人机交互子系统

1、分类用户,如:

  • 按技能水平:新手、初级、中级、高级;
  • 按职务:总经理、经理、职员;
  • 按所属集团:职员、顾客。

2、描述用户,如用户类型、使用系统达到的目的、特征(年龄、性别)、技能水平、事件跟踪图。

3、设计命令层次,如:

  • 研究现有的人机交互含义和准则;
  • 确定初始的命令层次;
  • 细化命令层次(次序、宽度和深度、操作步骤)。
  • 设计GUI(Graphical User Interface,图形用户界面)时,应与经典操作系统应用程序界面、操作风格一致。

4、设计人机交互类,与所使用的操作系统及编程语言关系密切。

3.4.3 任务管理子系统

1、分析并发性,如两个对象彼此之间不存在交互,或者同时接受事件。

2、主要内容:

  • 事件驱动型任务,表明数据到达的信号;
  • 时间驱动型任务,某些任务每隔一定时间被触发;
  • 优先任务,高(低)优先级,分离出来单独处理;
  • 确定关键任务,精心编码、严格测试;
  • 协调任务,当系统中存在3个以上任务时,就应该协调任务;
  • 确定资源需求,计算系统负载,估算占用CPU、内存的情况。

3.4.4 数据管理子系统

1、选择数据存储管理模式,如文件管理系统、关系数据库管理系统、面向对象数据库管理系统(OODBMS,Object-Oriented Database Management System)。

2、设计数据管理子系统:

  • 设计数据格式,针对不同的数据存储管理模式,采用不同的设计方法;
  • 设计相应服务,针对不同的数据存储管理模式,设计时也应有所侧重。

3.5 设计类中的服务

1、确定类中应有的服务;

2、实现服务:

  • 设计实现服务的算法;
  • 选择数据结构;
  • 定义内部类和内部操作。

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值