第五章 - 类的分析与设计

定义

  • 对未来系统的功能进行总体上的概括并使用UML的类图进行表达。
  • 在开始阶段粗略的对模型进行构建,后续再通过迭代逐级具体化,是一个逐步求精的设计过程。
  • 初始类图要覆盖所有需求的功能,并通过优化尽量保持业务结构的稳定,然后通过修订和丰富细节逐渐过渡到详细设计,并最终转化为成功的物理实现。

基本类的确定

  • 设计阶段的主要任务是从需求分析阶段的规格说明出发,对系统进行模型表示并优化。
  • 面向对象的概要设计首先寻找系统中参与业务处理的对象和类。
  • 然后使用类图(Class Diagram)将系统中不同的类抽象出来描述系统的静态结构,包括类以及它们之间的关系。

1.类及其种类

  • 在系统分析与设计阶段,类通常分为实体类(Entity Class)、控制类(Control Class)和边界类(Boundary Class)
    • 实体类:对应需求中的实体,通常需要永久保存,一般使用数据库表或文件来记录,既包括存储和传递-数据的类,还包括操作数据的类。(名词、POJO
    • 控制类:用于体现应用程序的执行逻辑,提供相应的业务操作,抽象控制类可以降低界面和数据库之间的耦合度。控制类有时也称为管理类。(动宾
    • 边界类:边界类用于对外部用户与系统之间的交互对象进行抽象,主要包括界面类以及与外部系统的数据交换类(如同步、缓存等)。
  • 在分析设计初始,通常首先识别出实体类,绘制初始类图,也可称为领域模型

2.类的识别/寻找类

  • 类的寻找和细化是迭代的过程,不断补充新类及信息并逐渐扩展,最后发展为更多的类和实例变量。
  • 需求规格说明书是寻找业务类的直接来源。
    • 一种比较快速而实用的分析方法是按照语法分析的方式将名词作为对象的候选,形容词作为属性(实例变量)的候选进行重点关注。
  • 业务术语词汇表也是类信息的重要来源,这些与业务术语相关的类通常为实体类。

3.初始类图/类图的基本画法(!)

在这里插入图片描述

  • 类名
  • 实例变量
  • 可见性
    • +, -, *, ~
  • 依赖(计算)属性
  • 类型(可忽略)
    • UML预定义
    • 编程语言提供
  • 类的便捷表示:<<entity>>
    在这里插入图片描述

4.类的关系/类图关系的画法(!)

  • 关联关系, Association, 静态,拥有
    • 自反关联(reflexive)
  • 导航方向, Navigation
  • 依赖关系, Dependency
    • 应避免双向依赖
      在这里插入图片描述
    • 属性“任务”其实无需显式的给出,因为它可以间接的通过与任务类之间的关联关系进行体现。
  • 关联关系的基数(多重性)
    • “*”:任意多个(包括0个)对象
    • “1”:只有1个对象
    • “3”:正好3个对象
    • “1…*”:最少1个,也可能为多个对象
    • “3…*”:至少3个,也可能为多个对象
    • “0…1”:0或1个对象
    • “3…7”:3到7个对象
  • 类与对象:系统中的每个对象在表示上具有唯一的标识ID以及通过其属性进行描述。这些属性称为实例变量(instance variable)或属性(attribute),同类对象可以用类来说明,即类为对象的模板
    • 连接类与对象间的实线,表示类图中关联关系的实例化
    • 对象名:类的类型
    • 实例变量的初始值

5.类的细化

5.1 方法和管理类(!)
  • 访问和修改方法,不涉及业务,在分析模型中通常不考虑,实现阶段再考虑。
  • 对象通常还提供了只需通过内部信息,如实例变量,对业务数据进行计算的方法。
    • 如方法realEffortCompute(),计算已经对项目中的任务和子项目分配的工作量。
  • 对于同类对象的协调和管理通常使用一个管理类,主要负责对对象的创建、代理访问其它对象的信息等。
  • 管理类应能够提供所管辖所有对象统一的处理方式。
5.2 控制类(!)
  • 控制类通常控制和协调不同对象的行为,用来封装用例的特有行为。复杂用例一般都需要一个或多个控制类。
  • 借助控制类可将边界对象与实体对象分开,让系统更能适应其边界内发生的变更。
  • 控制类还将用例所特有的行为与实体对象分开,使实体对象在用例和系统中具有更高的复用性。
  • 管理类一般处于Domain层,对同类实体提供管理服务。
  • 控制类一般处于业务控制层,驱动用例。
  • 控制类的识别:
    • 一般方法:先对所有的用例进行分析,对每个用例对应产生一个控制类,用来对该场景中需要的对象进行管理和协调。
    • 控制类每次考虑一个任务,只向控制类添加与该任务相关的方法和方法需要的实例变量。
    • 类与类之间尽可能保持较少的联系,这样可以降低接口的数量。
5.3 界面类(边界类)
  • 界面设计的基本要求是:通过界面使得(领域)模型中含有的(实体)类的某些部分对外部可见,比如用户通过界面可进行(某些)业务内容的修改或访问。
  • 对现有的类模型补充对应的界面描述,一个直接的方法就是对于每个类补充一个对应的接口,使得它向外部提供可访问的信息。
  • 对于项目类可设置一个ProjectMask界面,对外提供项目创建和修改的操作;使用一个控制类GUIControl,控制当前哪个类的界面类处于使用状态。(控制类用来驱动用例中的业务,边界类提供业务服务
    在这里插入图片描述

在这里插入图片描述

5.4 枚举类
  • 如果一个变量的取值是某个有限集合中的数据,如“红色”、“黄色”,“绿色”等,应该使用一种叫做枚举的类型而不是直接使用String类型。
  • 如图中所示的枚举类,其具有一个构造型<>描述,在它的实例变量部分例举的数据为该类型可能的取值
    枚举类
5.5 类设计优化
  • 优化可以提高模型的易理解性
  • 没有方法和实例变量的类将会被删除掉
  • 复杂功能的拆分
  • 利用抽象类隔离变化,利用泛化进行重用

顺序图(*)

1.顺序图定义

  • 对象轴、时间轴
  • 同步调用的方式和表示
  • 生命线、控制焦点(激活区域)
  • 同样可以使用通信图(协作图)进行交互建模
    在这里插入图片描述

2.对象的创建与删除

  • 对象的创建过程,箭头所指是一个新创建的对象,注意此对象名并不在最上方的位置出现。
    在这里插入图片描述
  • 右图是对象的删除过程,通过在生命线上的X符号表示对象在内存中被回收。
    在这里插入图片描述

3.结构表示

  • 顺序图某些部分使用矩形框封闭描述,左上角指定一种处理方式。
  • “opt”为可选的内容,表示在满足方括号条件的情况下,对应部分就会被执行,否则跳过。
  • “alt”对多分支的条件进行选择,矩形框内各分支用虚线分割。每个分支一个布尔条件,应彼此排斥。
  • “loop”为循环结构,这里必须清楚的给出循环执行的参数,如循环次数和结束条件。
    在这里插入图片描述
  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是第四章的部分习题及答案,希望对你有帮助。 1. 设计一个O(nlogn)时间复杂度的算法,找出一个整数数组中的最大差值,其中最大值必须位于最小值之后。 解答:可以使用分治法,将数组分成两部分,分别求出左边的最大值和右边的最小值,然后比较两个值之间的差值,取最大值即可。具体实现如下: ```python def max_diff(arr): if len(arr) < 2: return 0 mid = len(arr) // 2 left_max = max(arr[:mid]) right_min = min(arr[mid:]) return max(right_min - left_max, max_diff(arr[:mid]), max_diff(arr[mid:])) ``` 2. 设计一个算法,找出一个整数数组中的最大子序列和。 解答:可以使用动态规划法,定义一个状态数组dp,dp[i]表示以第i个元素结尾的最大子序列和,转移方程为:dp[i] = max(dp[i-1] + arr[i], arr[i])。最后返回dp数组中的最大值即可。具体实现如下: ```python def max_subarray(arr): if not arr: return 0 dp = [0] * len(arr) dp[0] = arr[0] for i in range(1, len(arr)): dp[i] = max(dp[i-1] + arr[i], arr[i]) return max(dp) ``` 3. 给定一个长度为n的整数序列,设计一个算法,找出其中第k大的数。 解答:可以使用快速排序的思想,每次选定一个pivot,将数组分成两部分,左边的元素都小于pivot,右边的元素都大于等于pivot。然后比较pivot的位置和k的大小,如果pivot的位置大于k,则在左边继续查找;如果pivot的位置小于k,则在右边继续查找。具体实现如下: ```python def quick_select(arr, k): if not arr or k > len(arr): return None pivot = arr[-1] left = [x for x in arr[:-1] if x < pivot] right = [x for x in arr[:-1] if x >= pivot] if len(right) == k - 1: return pivot elif len(right) > k - 1: return quick_select(right, k) else: return quick_select(left, k - len(right) - 1) ``` 4. 设计一个算法,找出一个无序整数数组中出现次数超过一半的数。 解答:可以使用摩尔投票法,遍历整个数组,维护一个候选数和计数器,如果当前元素等于候选数,则计数器加1;否则计数器减1。如果计数器归零,则将当前元素作为候选数。最后再遍历一遍数组,统计候选数的出现次数,如果出现次数超过一半,则返回该候选数。具体实现如下: ```python def majority_element(arr): if not arr: return None candidate = None count = 0 for num in arr: if count == 0: candidate = num count += (1 if num == candidate else -1) if arr.count(candidate) > len(arr) // 2: return candidate else: return None ``` 5. 设计一个算法,找出一个整数数组中的两个元素,使它们的和等于一个给定的数。 解答:可以使用哈希表,遍历整个数组,对于每个元素,如果它的补数已经在哈希表中,则返回它们的下标;否则将该元素加入哈希表中。具体实现如下: ```python def two_sum(arr, target): if not arr: return None table = {} for i, num in enumerate(arr): complement = target - num if complement in table: return (table[complement], i) else: table[num] = i return None ``` 希望这些答案能够帮助你解决算法设计分析第四章的部分习题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值