统一建模语言UML之类图(Class Diagram)(表示|关系|举例)

news2024/11/9 5:05:17

文章目录

  • 1.UML
  • 2.Class Diagram
    • 2.1 类图的表示
    • 2.2 类间的关系
      • 2.2.1 关联
      • 2.2.2 聚合
      • 2.2.3 组合
      • 2.2.4 泛化(继承)
      • 2.2.5 实现(接口实现)
      • 2.2.6 依赖
    • 2.3 类图的作用

参考:Class Diagram | Unified Modeling Language (UML)
UML是软件设计和面向对象编程中常用的一种标准化建模语言,对于可视化系统结构和功能非常有用,类图有多种不同类型的图:用例图,类图,时序图,活动图和状态图,每类图都有规范的表示,不局限于语言,本文介绍以下内容
(1)UML的图分类
(2)类图的表示
(3)类图的关系
(4)类图的作用

1.UML

Unified Modeling Language(UML)是一种标准化的建模语言,用于在软件系统开发过程中可视化、描述和设计软件的结构与行为。UML 提供了一系列图表,帮助开发人员、系统架构师以及相关人员交流系统的设计和功能。UML 包括许多不同类型的图:

  • 用例图(Use Case Diagram):描述系统的功能需求以及外部参与者的交互
  • 类图(Class Diagram):描述系统的静态结构,展示类、属性、方法以及类之间的关系
  • 时序图(Sequence Diagram):展示对象之间的消息传递顺序,描述时间序列中的动态行为
  • 活动图(Activity Diagram):用于表示系统中的流程和业务逻辑
  • 状态图(State Diagram):描述系统或对象的状态以及状态之间的转换

2.Class Diagram

2.1 类图的表示

在类图中,类用方框表示,每个方框包含三个部分:类名,属性和方法,方框之间的连接线说明这些类的关系。类图提供了系统设计的高级概述,有助于沟通和记录软件的结构。它们是面向对象设计的基本工具,在软件开发生命周期中起着至关重要的作用。

在这里插入图片描述
如图所示的方框为类Car的类图表示

  • Class Name:第一个小框描述了类名,通常放在方框中间加粗,类民首字母大写
  • Attributes:第二个小框介绍了类的属性(字段),包括属性名,属性的可见性和数据类型
  • Methods:第三个小框介绍了类的方法,代表了类的行为函数,包括可见性,返回类型和参数
  • Visibility:可见性表示了属性和方法的可获取水平
    (1)+:public公共,对所有类可见
    (2)-:private私有,仅在类内可见
    (3)#:protected保护,对子类可见
    (4)~:包或默认可见性,对同一包中的类可见
  • Parameter:方法中的参数显示了类之间的信息流动
    (1)in:输入参数是从调用对象(client)到被调用对象(server)的参数
    (2)out:输出参数是从被调用对象(server)到调用对象(client)的参数
    (2)inout:输入输出参数同时作为输入和输出,在client和server之间进行信息流通

2.2 类间的关系

在类图中,类之间的关系有以下几种:
在这里插入图片描述
比较常见的分类是6种:关联,聚合,组合,泛化(继承),实现,依赖,还有一些概念更细分的,比如直接关联,使用依赖等。

关系描述
关联Association表示类之间的长期持久关系,一个类持有另一个类的引用,通常通过成员变量表示
聚合Aggregation整体和部分关系,部分可以独立于整体
组合Composition整体和部分关系,部分不能独立于整体
泛化Generalization子类继承父类属性和方法,可扩展和重写
实现Realization通过抽象类定义接口,客户端和实现解耦
依赖Dependency表示类之间临时的关系,一个类需要短暂使用另一个类的某个功能,通常通过方法调用实现

2.2.1 关联

此处介绍两种:关联和直接关联,由于概念比较类似放在一个小节

(1)关联Association:是泛指两个类之间的关系,可以是双向或单向,也可以是弱耦合的逻辑联系,用直线表示

在这里插入图片描述

关联举例:选课系统中学生和课程之间是双向关联,学生可以注册多门课程,每门课程可以有多个学生,Student类和 Course类存在关联关系,但是并不代表Student类直接引用 Course类的实例。如下面代码所示,student1和course1的实例创建是独立的,但是student1中的enroll方法会用到course1,course1的add_student也会添加student1

class Student:
    def __init__(self, name):
        self.name = name
        self.courses = []  # 一个学生可以注册多门课程

    def enroll(self, course):  # 学生注册课程,课程添加学生
        self.courses.append(course)
        course.add_student(self)

class Course:
    def __init__(self, title):
        self.title = title
        self.students = []  # 一门课程可以有多个学生

    def add_student(self, student):  
        self.students.append(student)

# 创建实例
student1 = Student("Alice")
course1 = Course("Math")

# 学生注册课程
student1.enroll(course1)

(2)直接关联Direct Association:强调单向依赖关系,一个类直接持有或依赖另一个类的实例,用带单向箭头的直线表示,箭头指向被持有的类。

直接关联是关联的一种更具体的表现,表示类之间有更明确的耦合关系

在这里插入图片描述

直接关联举例:学生和身份证之间存在一种直接关联。每个学生都必须有一个身份证,学生对象直接持有身份证对象。Student类和IDCard类之间有一个单向的直接关联,这是一种更强的依赖关系,表示Student 类的对象必须持有一个 IDCard 类的对象才能正常工作。如下面代码所示,student的实例创建必须用到id_card实例

class IDCard:
    def __init__(self, card_number):
        self.card_number = card_number

class Student:
    def __init__(self, name, id_card):
        self.name = name
        self.id_card = id_card  # 学生直接持有身份证的引用

# 创建身份证实例
id_card = IDCard("123456789")
student = Student("Alice", id_card)

# 访问学生的身份证信息
print(student.id_card.card_number)  # 输出: 123456789

2.2.2 聚合

  • 聚合Aggregation:一种特殊的关联形式,表示整体—部分(whole-part)关系,它表示一种更强的关系,其中一个类(整体)包含或由另一个类(部分)组成,在这种关系中,子类可以独立于其父类而存在。用带空心菱形箭头的直线表示,箭头指向整体
    在这里插入图片描述

聚合举例:公司拥有员工,但是员工可以在没有公司的情况下存在。换句话说,公司雇佣了员工,但员工可以辞职并加入另一家公司,因此公司和员工之间的关系是聚合。Company 是整体,Employee 是部分,如下面代码所示,company实例由employee1和employee2实例组成,但是删除company并不会影响employee1和employee2

class Employee:
    def __init__(self, name):
        self.name = name

    def work(self):
        print(f"{self.name} is working.")

class Company:
    def __init__(self, name):
        self.name = name
        self.employees = []  # 聚合关系,公司由多个员工组成

    def hire(self, employee):
        self.employees.append(employee)
        print(f"{employee.name} has been hired by {self.name}.")

    def list_employees(self):
        print(f"{self.name} has the following employees:")
        for emp in self.employees:
            print(f"- {emp.name}")

# 创建公司和员工实例
employee1 = Employee("Alice")
employee2 = Employee("Bob")
company = Company("TechCorp")

# 公司雇佣员工
company.hire(employee1)
company.hire(employee2)

# 公司列出员工
company.list_employees()

# 即使公司不存在,员工仍然可以存在
del company
employee1.work()  # 输出: Alice is working.

2.2.3 组合

  • 组合Composition:一种更强的聚合形式,表示更重要的所有权或依赖关系。在组合中,部分类不能独立于整体类而存在。组合带实心菱形箭头的直线表示,箭头指向整体

在这里插入图片描述

组合举例:手机里通讯录和联系人的关系是组合关系,如果通讯录被删除,那么里面的联系人也会删除,也就是说联系人不能独立于通讯录存在。ContactBook 是整体,Contact 是部分

class Contact:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

    def display_contact(self):
        print(f"Name: {self.name}, Phone: {self.phone}")

class ContactBook:
    def __init__(self):
        self.contacts = []  # 组合关系,通讯录拥有多个联系人

    def add_contact(self, name, phone):
        contact = Contact(name, phone)  # 创建联系人的同时,直接把它归属到通讯录
        self.contacts.append(contact)

# 创建通讯录实例
contact_book = ContactBook()

# 向通讯录添加联系人
contact_book.add_contact("Alice", "123-456-7890")
contact_book.add_contact("Bob", "987-654-3210")
# 删除通讯录
del contact_book
# 联系人对象也会随之销毁,无法独立存在

2.2.4 泛化(继承)

  • 泛化Generalization(继承Inheritance):表示类之间的“is-a”关系,其中一个类(subclass或child)继承另一个类(supclass或parent)的属性和行为,继承使得子类能够复用父类的代码,同时可以扩展或重写父类的功能。用一条带空心三角箭头的实线表示,箭头指向父类
    在这里插入图片描述

继承举例:一个银行账户下的储蓄账户和信用账户可以共用这个银行账户的信息,BankAccount是父类,SavingsAccount 是子类,CreditAccount 是子类

# 父类:BankAccount
class BankAccount:
    def __init__(self, account_number, balance):
        self.account_number = account_number  # 账户号码
        self.balance = balance  # 账户余额
    
    def deposit(self, amount):
        """存款方法"""
        self.balance += amount
        print(f"Deposited {amount}. New balance: {self.balance}")

    def withdraw(self, amount):
        """取款方法"""
        if amount > self.balance:
            print("Insufficient funds!")
        else:
            self.balance -= amount
            print(f"Withdrew {amount}. New balance: {self.balance}")

# 子类:SavingsAccount
class SavingsAccount(BankAccount):
    def __init__(self, account_number, balance, interest_rate):
        super().__init__(account_number, balance)
        self.interest_rate = interest_rate  # 储蓄账户的利率
    
     def add_interest(self):
        """添加利息"""
        interest = self.balance * self.interest_rate
        self.balance += interest
        print(f"Interest added: {interest}. New balance: {self.balance}")

# 子类:CreditAccount
class CreditAccount(BankAccount):
    def __init__(self, account_number, balance, credit_limit):
        super().__init__(account_number, balance)
        self.credit_limit = credit_limit  # 信用账户的信用额度

    def withdraw(self, amount):
        """重写父类的取款方法,允许透支"""
        if amount > self.balance + self.credit_limit:
            print("Exceeds credit limit!")
        else:
            self.balance -= amount
            print(f"Withdrew {amount}. New balance: {self.balance}")

# 测试代码
savings = SavingsAccount("12345", 1000, 0.05)
savings.deposit(500)
savings.add_interest()

credit = CreditAccount("67890", 500, 1000)
credit.withdraw(200)
credit.withdraw(1500)  # 允许透支
credit.withdraw(2000)  # 超过信用额度

2.2.5 实现(接口实现)

  • 实现Realization(接口实现Interface Implementation):是在面向对象设计中,通过接口或抽象类来定义某些功能,来描述某一组行为的约定,而具体的实现由不同的类来完成。可以避免直接依赖具体类,而是依赖接口或抽象类,从而实现代码的解耦。用带空心三角箭头的虚线表示,箭头指向接口
    在这里插入图片描述

实现举例:有一个支付系统,它支持多种支付方式,如信用卡支付,PayPal 支付和比特币支付,每种支付方式都有自己的具体实现方式,但它们都应该符合统一的支付行为,比如 pay()。比如下面代码中,IPayment是一个抽象类,也就是客户端接口,声明了一个pay()方法,但是没有具体实现,而CreditCardPayment,PayPalPayment和BitcoinPayment都会各自具体实现pay(),对于客户端代码process_payment传入任何一个payment_method,都可以使用pay(),客户端代码不关心具体是哪种支付方式,只需要知道它实现了IPayment 接口即可。

from abc import ABC, abstractmethod

# 定义一个支付接口(抽象基类)
class IPayment(ABC):
    @abstractmethod
    def pay(self, amount):
        """支付方法,所有支付方式都必须实现"""
        pass

# 具体实现:信用卡支付
class CreditCardPayment(IPayment):
    def pay(self, amount):
        print(f"Paid {amount} using Credit Card.")

# 具体实现:PayPal 支付
class PayPalPayment(IPayment):
    def pay(self, amount):
        print(f"Paid {amount} using PayPal.")

# 具体实现:比特币支付
class BitcoinPayment(IPayment):
    def pay(self, amount):
        print(f"Paid {amount} using Bitcoin.")

# 客户端代码,使用支付系统
def process_payment(payment_method, amount):
    payment_method.pay(amount)

# 测试代码
credit_card = CreditCardPayment()
paypal = PayPalPayment()
bitcoin = BitcoinPayment()

# 使用不同的支付方式处理支付
process_payment(credit_card, 100)
process_payment(paypal, 200)
process_payment(bitcoin, 300)

这种实现关系可以很容易地为系统添加新的实现方式(如支持新的支付方式),而不需要修改现有代码,新增的实现类只需要实现接口即可,完全可以独立于其他代码进行开发,将客户端代码与具体实现解耦来提高系统的可维护性,如果不使用实现关系,直接让 process_payment 依赖于具体的支付类,那么就会出现下面这种不停维护客户端代码的情况

def process_payment(payment_method, amount):
    if isinstance(payment_method, CreditCardPayment):
        payment_method.pay(amount)
    elif isinstance(payment_method, PayPalPayment):
        payment_method.pay(amount)
    elif isinstance(payment_method, BitcoinPayment):
        payment_method.pay(amount)
    # 如果以后新增一种支付方式,还要在这里加新的条件分支

2.2.6 依赖

  • 依赖Dependency:表示一个元素对另一个元素的使用或依赖,但这种关系不像关联或继承那么强,它表示类之间更松散的耦合连接,典型场景是类的方法依赖于另一个类的对象作为参数或返回。 用带普通箭头的虚线表示,箭头指向被依赖者
    在这里插入图片描述

依赖举例:办公室工作人员会使用打印机打印东西,OfficeWorker 依赖 Printer,但并没有保存 Printer 的实例,它只在需要打印时使用Printer

class Printer:
    def print_document(self, document):
        print(f"Printing: {document}")

class OfficeWorker:
    def __init__(self, name):
        self.name = name

    def do_work(self, document, printer):
        printer.print_document(document)

使用依赖Usage Denpency是依赖的一种特定形式,表示一个类(client)利用或依赖另一个类(server)来执行某些任务或访问某些功能。client类依赖于server类提供的服务,但不拥有或创建其实例,上面的打印机例子也是一种使用依赖,此处不再细分描述

2.3 类图的作用

  • 建模类结构:类图通过表示类及其属性、方法和关系,帮助对系统结构进行建模,提供了系统架构的清晰而有条理的视图
  • 理解关系:类图描绘了类之间的关系,例如关联、聚合、组合、继承和依赖关系,有助于开发设计等人员了解系统结构
  • 实施蓝图:类图是软件实施的蓝图,通过说明类、它们的属性、方法及其之间的关系来指导开发人员编写代码
  • 代码生成:一些软件开发工具和框架支持从类图生成代码,开发人员可以从可视化表示中生成大量代码,从而减少手动错误的可能性并节省开发时间
  • 识别抽象和封装:类图能识别抽象以及在类中封装数据和行为,支持面向对象设计的原则,例如模块化和信息隐藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024/9/12 数学“回头看”之R(a)与R(a※)、分布函数、概率密度的特点

注意!这是充分必要条件。 分布函数性质 概率密度性质:

如何使用Jmeter关联influxDB?

一、添加"添加后端监听器" 二、后端监听器实现选择,"org. apache. jmeter. visualizers. backend. influxdb.InfluxdbBackendlistenerClient" 三、修改"influxdbUrl:自己的主机、application:取一个项目名" 四、influxDB&…

SAP B1 学习笔记 - 易混淆字段名(持续更新中)

背景 在 SAP B1 的单据中,由于同一单据时常对应着多个后台表单,且后台表单内包含的字段信息往往远大于单据显示出来的,在配置时经常出现多个字段混淆、无系统信息提示字段名模糊的情况,这里总结常见的易混淆难查找的后台字段名。…

【MySQL】MySQL表的增删改查(进阶篇)——之查询操作(超级详解)

前言: 🌟🌟本期讲解关于MySQL表增删查改进阶篇,希望能帮到屏幕前的你。 🌈上期博客在这里:http://t.csdnimg.cn/8SiWF 🌈感兴趣的小伙伴看一看小编主页:http://t.csdnimg.cn/8SiWF ​…

SpringBoot父子工程搭建

SpringBoot父子工程搭建 1、父工程 1.1、创建父工程 1.2、移除无用文件 1.3、修改pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XML…

循环节,CF 314B - Sereja and Periods

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 314B - Sereja and Periods 二、解题报告 1、思路分析 如果 b 个 a 中出…

【Python报错已解决】AttributeError: ‘str‘ object has no attribute ‘read‘

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 前言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路 二、解决方法2.1 方法一&#xff1a;直接使用字符串2.2 步骤…

DWI扩散磁共振成像和结构连接组学指南

扩散磁共振成像和结构连接组学指南 引言流程概述扩散磁共振成像(dMRI)dMRI基础ADC&#xff08; apparent diffusion coefficient, 表观扩散系数&#xff09;MD&#xff08;mean diffusivity, 平均扩散率&#xff09;FA&#xff08; fractional anisotropy, 分数各向异性&#x…

安装FTP服务器教程

一。安装vsftpd yum install vsftpd 二。修改配置文件&#xff0c;匿名账户具有访问&#xff0c;上传和创建目录的权限 vim /etc/vsftpd/vsftpd.conf &#xff08;红色进行设置放开YES&#xff09; local_enable&#xff1a;本地登陆控制&#xff0c;no表示禁止&#xff0c;ye…

llama网络结构及源码

模型初始化 首先模型初始化&#xff0c;确定模型属性 class LLaMA(nn.Module):def __init__(self, config: LLaMAConfig) -> None:super().__init__()assert config.padded_vocab_size is not Noneself.config configself.lm_head nn.Linear(config.n_embd, config.pad…

5 模拟——59. 螺旋矩阵II ★★

5 模拟 59. 螺旋矩阵II 给你一个正整数n,生成一个包含 1 到 n2所有元素,且元素按顺时针顺序螺旋排列的nn正方形矩阵 matrix 。 示例1: 输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]] 示例2: 输入:n = 1 输出:[[1]] 算法设计 本题与上一题【54. 螺旋矩阵】不同,上一…

1、https的全过程

目录 一、概述二、SSL过程如何获取会话秘钥1、首先认识几个概念&#xff1a;2、没有CA机构的SSL过程&#xff1a;3、没有CA机构下的安全问题4、有CA机构下的SSL过程 一、概述 https是非对称加密和对称加密的过程&#xff0c;首先建立https链接需要经过两轮握手&#xff1a; T…

redis基本数据结构-hash

这里写自定义目录标题 1. redis的数据结构hash1.1 Hash 数据结构的特点1.2 常见命令1.3 适用示例 2. 常见业务场景2.1 用户信息存储2.1.1 场景2.1.2 优势2.1.3 解决方案2.1.4 代码实现 2.2 购物车管理2.2.1 背景2.2.2 优势2.2.3 解决方案2.2.4 代码实现 3. 注意事项&#xff1a…

使用虚拟信用卡WildCard轻松订阅POE:全面解析平台功能与订阅方式

POE&#xff08;Platform of Engagement&#xff09;是一个由Quora推出的人工智能聊天平台&#xff0c;汇集了多个强大的AI聊天机器人&#xff0c;如GPT-4、Claude、Sage等。POE提供了一个简洁、统一的界面&#xff0c;让用户能够便捷地与不同的AI聊天模型进行互动。这种平台的…

Shadertoy和desmos用来快速图像化辅助计算的好工具

Desmos适用场景解直线方程例子 Shadertoy是一个专门通过shader片段利用gpu像素着色的工具。每一帧都会执行显示区域每个像素点的着色。默认片段坐标是左下角(0,0)到右上角(像素分辨率大小)。有网页版&#xff0c;也有vscode插件版。插件版更方便.如果要验证一些图像化的计算。…

MyBatis-Plus分页查询、分组查询

目录 准备工作1. 实体类2. Mapper类3. 分页插件4. 数据 分页查询1. 使用条件构造器2. 使用自定义sql 分组查询1. 分组结果类2. 自定义sql3. 测试类 准备工作 1. 实体类 对地址字段address使用字段类型转换器&#xff0c;将List转为字符串数组保存在数据库中 package com.exa…

(web自动化测试+python)1

一.UI自动化测试介绍 1.测试化理论 UI就是指的是用户接口&#xff0c;指的是用户与电脑的接口&#xff0c;是用户界面 UI不仅仅指的是web&#xff0c;还可以指代app 我们为什么要进行自动化&#xff1f; 大量版本的回归 当新的功能出现&#xff0c;复测之间的--我们叫做回归&am…

《Diffusion Models Without Attention》CVPR2024

摘要 这篇论文探讨了在高保真图像生成领域&#xff0c;去噪扩散概率模型&#xff08;Denoising Diffusion Probabilistic Models, DDPMs&#xff09;的重要性。尽管DDPMs在捕捉复杂视觉分布方面表现出色&#xff0c;但在高分辨率图像生成上面临显著的计算挑战。现有的方法&…

动物目标检测——基于YOLOv5和树莓派4B平台

目标检测在计算机视觉领域中具有重要意义。YOLOv5&#xff08;You Only Look One-level&#xff09;是目标检测算法中的一种代表性方法&#xff0c;以其高效性和准确性备受关注&#xff0c;并且在各种目标检测任务中都表现出卓越的性能。本文将详细介绍如何在性能更强的计算机上…

java实习生第一次被分配需求——完成需求的大概流程

一、分配需求后第一步&#xff0c;首先是把项目跑起来 在我进入公司一两个星期之后&#xff08;基本熟悉了公司的框架&#xff09;&#xff0c;就被我所在的开发小组的某个大哥分派了一个需求&#xff0c;然后他给我发了一个git地址&#xff0c;以及一个git的分支&#xff08;…