面向对象方法-UML
概述
在软件开发中,我们经常需要向他人清晰地展示功能设计,或快速理解他人的项目。UML(统一建模语言)作为一项标准化的建模工具,能够帮助我们高效地描述系统的静态结构和动态行为,从而提升沟通效率、加深系统理解并降低开发风险。本文将重点介绍 UML 中的用例图和类图,以帮助您更好地掌握 UML 的基本概念和实际应用。
UML 定义
UML(Unified Modeling Language)是一种在软件工程中广泛使用的标准化建模语言。它通过一套图形化的符号和规则,来表示系统的静态结构和动态行为。
起源和发展
UML 由 Grady Booch、James Rumbaugh 和 Ivar Jacobson 在 20 世纪 90 年代初共同开发,初衷是统一当时存在的多种面向对象的建模方法,使软件开发人员能够使用一种通用的语言进行建模。
用途
- 规划:在规划阶段,UML 有助于捕捉和描述系统的功能需求,帮助定义系统的功能边界。
- 设计:在设计阶段,UML 可以帮助开发人员定义系统的结构和行为,清晰地表达系统的模块、类及其相互关系,从而使设计更加直观和规范
- 实现与维护:作为技术文档的一部分,提供对系统架构的全面视图,有助于后续的系统实现、维护和扩展,也帮助团队成员理解系统的设计和实现细节
UML 在软件开发生命周期中的应用
- 捕捉和描述系统的功能需求,展示系统用户(参与者)和系统之间的交互,帮助定义系统的功能边界。
- 定义系统的概念模型,展示关键业务对象及其关系,设计系统的静态结构,定义类、属性、方法及类之间的关系。
用例图
定义
用例图(Use Case Diagram)是一种行为图,用于描述系统的功能需求以及用户与系统之间的交互。通过用例图,开发团队可以明确系统需要实现的功能及其使用方式
作用
- 帮助分析和定义系统的功能需求。
- 直观展示用户与系统的交互,便于与利益相关者沟通和确认需求。
- 为后续的设计和实现提供基础。
基本元素
- 参与者(Actors):系统外部实体,如用户、其他系统。
- 用例(Use Cases):系统功能或服务,描述参与者与系统交互。
- 关系:包括包含(Include)、扩展(Extend)、泛化(Generalization)、依赖(Dependency)和关联(Association)等。
一个基本的用例图示例
几种用例之间的关系示例
包含关系
包含关系指的是两个用例之间,其中一个用例(基本用例)的行为包含了另外一个用例(包含用例)。 在 UML 图中,包含关系用带箭头的虚线表示,并且线上标有<>,箭头的方向是从基本用例到包含用例。
扩展关系
扩展关系是对基本用例的扩展,基本用例是一个完整的用例,即使没有子用例参与,也可以完成一个完整的功能。扩展的基本用例中存在一个扩展点,只有扩展点被激活时,子用例才会被执行。扩展关系是从扩展用例到基本用例的关系,它说明扩展用例如何插入到基本用例中。
正确使用
- 用例图应简洁,只展示主要用例。
- 参与者和用例关系应明确。
案例学习
错误示例 1
错误分析:用例图过于复杂,细节过多 问题: 用例图包含过多细节,导致复杂度过高,不易理解。 解决方法: 用例图应保持简洁,只展示主要用例,详细流程可以在其他图表中展示。
正确示例 1
错误示例 2
错误分析:用例之间缺少关联关系 问题: 各用例之间没有关联关系,未能体现用例的依赖或包含关系。 解决方法: 使用包含关系或扩展关系来表示用例之间的依赖
正确示例 2
常见错误及避免方法
- 用例过于详细或笼统
- 过于详细的用例图容易使图变得复杂,不利于理解。
- 过于笼统的用例图则可能遗漏重要的功能需求。 避免方法:保持用例图的适当粒度,确保每个用例描述一个具体功能。
- 参与者角色不明确
- 未明确区分参与者的不同角色,容易导致混淆。 避免方法:确保参与者角色明确,并与相应的用例准确关联。
类图
定义
类图(Class Diagram)是一种结构图,用于描述系统的静态结构,展示系统中类、接口及其关系。 类图展示了类的属性、方法及类之间的关系,如继承、实现、关联等。
作用
- 帮助理解和设计系统的静态结构。
- 提供系统类的详细描述,为代码实现提供蓝图。
- 促进开发团队对系统架构和设计的理解和沟通。
基本元素
- 类(Classes):表示系统中的一个对象类型,包含属性和方法。类通常用一个矩形表示,矩形分为三部分:类名、属性和方法。
- 属性(Attributes):表示类的特性或数据,通常在类图中显示在类名下方的部分。
- 方法(Methods):表示类的操作或行为,通常在类图中显示在属性下方的部分。
- 关系(Relationships):包括关联(Association)、聚合(Aggregation)、组合(Composition)、继承(Generalization)、实现(Realization)、依赖(Dependency)。
类图的关系
关联(Association):实线箭头,两个类之间的关系,表示一个类的实例可以与另一个类的实例相关联。 A 类与 B 类之间有一个关联关系,用实线表示。 依赖(Dependency):虚线箭头,一个类依赖于另一个类,通常表示使用关系,例如一个类的方法中使用了另一个类作为参数或局部变量。 A 类依赖于 F 类,用虚线箭头表示,箭头指向 F 类。 聚合(Aggregation):空心菱形和实线。表示整体和部分的关系,但部分可以独立于整体存在。 A 类聚合了 C 类,用空心菱形和实线表示,菱形在 A 类的一端。 组合(Composition):实心菱形和实线。表示整体和部分的强关系,部分不能独立于整体存在。 A 类组合了 D 类,用实心菱形和实线表示,菱形在 A 类的一端。 继承(Generalization):空心箭头和实线。表示类与子类之间的关系,子类继承父类的属性和方法。 E 类继承了 A 类,用空心箭头和实线表示,箭头指向 A 类。 实现(Realization):空心箭头和虚线。表示类实现接口,类提供接口定义的方法实现。 E 类实现了接口 I,用空心箭头和虚线表示,箭头指向接口 I。
正确使用
合理的类和关系设计:类图应清晰展示系统的结构,类的属性和方法应合理定义。类之间的关系应准确表示,包括继承、实现、关联、聚合和组合等。 继承和实现关系应清晰展示:继承关系应清晰,父类和子类之间的关系应明确表示。实现关系应准确,类与接口之间的实现关系应清晰展示。
案例学习
案例 1
错误分析 错误的依赖关系(School ..> Teacher : employs): 在实际中,雇佣关系应该是更强的关联关系或聚合关系。依赖关系(虚线箭头)通常用于表示临时的、弱的关系,如方法参数,而雇佣关系是长期的
组合关系误用(Teacher *-- Course): 组合关系表示生命周期的依赖性,但课程的生命周期不应该依赖于教师。正确的关系应该是依赖关系。
错误的关联关系(Student -- Course): 使用了普通的实线关联关系,但没有准确表达学生与课程之间的动态依赖。正确的关系应该是依赖关系。
聚合关系误用(Student o-- Homework): 聚合关系表示部分可以独立于整体存在,但作业是学生的一部分,正确的关系应该是组合关系。
正确示例
如何区分依赖、关联、聚合、组合关系? 依赖关系表示一个类使用到另一个类的功能,这种关系是临时的和使用上的 特点:临时性的,A 类使用 B 类的某些功能,B 类可以独立存在,B 的变更会影响到 A
关联关系表示类之间的基本连接,表示一个类的对象可以知道另一个类的对象 特点:持久性的,双向或单向的导航
聚合关系是一种特殊的关联关系,表示一个类包含另一个类的对象,但这些对象在其生命周期内独立存在。 特点:整体-部分关系,部分可以独立于整体存在
组合关系也是一种特殊的关联关系,表示一个类包含另一个类的对象,且这些对象在包含类的生命周期内依赖存在。 特点:强整体-部分关系,部分不能独立于整体存在
案例 2
错误分析 错误的实现关系(Person <|-- Teacher): Teacher 类与 Person 接口之间使用了继承关系(空心箭头),这是错误的。接口应该使用实现关系(带虚线的空心箭头)。
错误的继承关系(School <|-- Course): School 类与 Course 类之间使用了继承关系(空心箭头),这是错误的。Course 不应该是 School 的子类,它们之间没有父子类的关系。
正确示例
如何区分继承、实现关系? 继承关系表示一个类(子类)从另一个类(父类)继承属性和方法,形成**“is-a”**的关系,例如苹果-水果 特点: 父类与子类之间的关系,子类继承父类的所有属性和方法 子类可以重写父类的方法,子类是父类的特化(specialization),是对父类的一种更具体、更详细的表达
实现关系表示一个类(实现类)实现了一个接口(interface)或抽象类,形成**"can-do"**的关系, 特点: 接口或抽象类与实现类之间的关系,实现类必须实现接口或抽象类定义的所有方法 实现类可以有多个接口,实现类是接口的实现(realization)
案例 3
错误分析 问题: 类图过于复杂,包含太多的属性和方法,导致难以阅读和理解。 解决方法: 类图应保持简洁,只展示主要属性和方法,详细的实现可以在文档中描述。
正确示例
常见错误及避免方法
- 类设计过于复杂或简单 类图过于复杂会使图难以理解,过于简单则可能遗漏重要信息。 避免方法:保持适当的粒度,确保类的属性和方法合理,关系清晰。
- 类图关系混乱 类之间的关系不明确,容易导致误解和设计错误。 避免方法:确保关系清晰、准确,并合理使用继承、实现、关联、聚合和组合等关系。
总结
正确使用 UML 的好处
- 提高沟通效率:使用 UML 图表,开发团队可以更高效地沟通系统需求和设计,减少误解和信息遗漏。UML 提供了一种通用的表达方式,使得不同背景的团队成员能够更容易理解系统模型。
- 增强系统理解:UML 图表帮助开发人员更全面地理解系统的结构和行为,促进系统分析和设计的深入思考。通过直观的图形表示,开发人员可以更容易识别系统中的关键组件和交互关系。
- 降低开发风险:在项目早期使用 UML 进行建模,可以发现和解决潜在的问题,减少后期修改的成本。UML 图表提供了系统的全局视图,有助于确保各个部分设计的一致性和完整性。