文章目录
写在前面:
这门课中所有的图都要掌握,都可能会考。今年考了ERD,DFD,UML类题,状态机图,时序图,活动图以及用例图。
同时也要对基础概念背诵抓紧,尽管饶老师说只考理解,不考背诵,但是还是建议背一下,不然就要像我一样面对数据库完整性发懵了😭
建议背一下1NF,2NF,3NF定义,类题优化(几乎必考),类图设计原则,数据库嵌套查询(看一下),数据库完整性等知识,血的教训🩸
需要掌握的图
DD
数据字典分为四种
1️⃣ 数据流字典
2️⃣数据存储字典
3️⃣数据处理字典
4️⃣数据项字典
数据流字典
数据流字典(F1~Fn):
编号 | 名称 | 来源 | 去向 | 所含数据结构 | 说明 |
---|---|---|---|---|---|
F1 | 用户信息 | S1 | D1 | 用户细节 | 用户提交注册表单的用户数据 |
数据存储字典(D1~Dn):
编号 | 名称 | 插入数据流 | 输出数据流 | 内容 | 说明 |
---|---|---|---|---|---|
D1 | 用户 | F1(S1-D1) | F2(D1-S2) | 编号、细节 | 用于存储有关用户的信息 |
数据处理字典(P1~Pn):
编号 | 名称 | 来源 | 处理逻辑概括 | 输出数据流 | 说明 |
---|---|---|---|---|---|
P1 | 登录用户数据 | F1 | 读入用户数据,写入用户文件中去 | F2 |
数据项字典(I1-01~In-n):
给出数据描述的部分内容,对数据流图中的各个存储文件中的记录字段予以逐个定义
编号 | 名称 | 类型 | 长度 | 说明 | 备注 |
---|---|---|---|---|---|
I1-01 | 用户密码 | 字符型 | 50 | 用户账号密码 |
DFD
步骤分为三步走:
数据流图 = 数据流 + 图
1️⃣ 确定系统的输入输出
2️⃣ 由外向里画系统的顶层数据流图;
3️⃣ 自顶向下逐层分解,绘出分层数据流图。
数据流四大要素
外部实体指系统之外、又与系统有联系的人或事物,它表达了该系统数据的外部来源和去处;
数据加工: 描述输入数据流到输出数据之间的变换,也就是输入数据流经过什么处理后变成了输出数据。
数据存储: 某种数据保存后的逻辑统称,不是指保存数据的物理地点和物理介质。每个数据存储都有一个名字。
数据流: 处理功能的输入/输出,箭头表示数据流向。
自顶向下分解指的是从顶层数据流图分解到下层的流图的过程。所以先画出顶层图,我们再细化出更加详细的0层图,一层图~~~
注意事项:顶层图只有一张,图中的“数据加工”也只有一个,不必为其编号。
e.g :
要注意一个对象可以出现多次
然后我们自顶向下分解顶层图,将其功能细化。
0层图:就是把顶层图的“加工”分解成若干个“子加工”,并用数据流将这些“子加工”连接起来,使得顶层图的输入数据经过若干“子加工”处理后,变成顶层图的输出数据流。
0层图本质上就是将顶层图中销售管理系统细化出了各个功能。
接下来,逐层对于加工操作逐渐细化。
数据流图只反映系统逻辑功能
分层的数据流图总是由顶层、中间层和底层组成的(或:上下文图+0级图+n级图) :
顶层数据流图确定了系统的边界
中层图描述了某个处理过程的分解,而组成部分要进一步被分解
底层图描述的是无须分解的基本处理过程
每个加工至少应有一个输入数据流(反映被处理数据的来源)和 一个输出流(反映加工的结果)
DFD与数据字典结合:
此处数据字典分为
1️⃣数据流:和上面的一样
2️⃣数据元素:流动过程中流动的东西(学号)
3️⃣数据存储:同上
4️⃣数据处理:同上
5️⃣外部项:实体对象
例子:
ER
注意ERD与UML区别:是否包含方法
如何确定连接是用实线还是虚线:
以客户(Customer)和订单(Order)的关系为例,客户拥有唯一的识别信息CustomerID,订单拥有一个流水号。
第一种情况,假如该流水号是整个系统范围内的,那么仅仅流水号字段就可以唯一地确定订单的身份。订单中包含的CustomerID属性是客户实体的主键, 但不是订单实体的主键,相当于纯粹外键(PURE FOREIGN KEY)。客户实体和订单实体之间的关系就是非决定关系,因为CustomerID字段无法决定订单的身份。非决定关系是虚线。
第二中情况,假如该流水号不是整个系统范围内的,而是每个客户一个流水号。比如,你第一次在太平洋百货购物的话,你的流水号是1,下次就是2,依次递增。 那么,仅仅流水号字段本身就无法确定订单的身份,还需要CustomerID字段联合作主键方可。这个时候,CustomerID即是客户实体的主键,又 是Order实体的主键,相当于MIXED FOREIGN KEY.这种关系是决定关系,因为CustomerID也参与了确定订单身份的职责,尽管是部分。决定关系是实线。
简言之既是外键又是主键才用实线,否则虚线
包含内容:
实体名称
主键 : (PK)
外键: (FK)
实体属性
关系:
一对一:
一对多:
多对多:
Use-Case
包含着以下的元素
1️⃣参与者:代表的是参与使用系统的一类角色,例如,读者就是图书馆这个系统的参与者。要正确把握参与者,需要注意以下几点:
- 参与者本身并不属于系统结构之中,位于系统之外;
- 参与者代表的是一类角色而不是一个具体对象,换言之,你可以说参与者是猪,而不能说参与者是“佩奇”;
- 参与者不一定是人,也可以是另一个外部的系统、环境等等。
2️⃣用例:每个用例代表系统能够提供的一类功能,UML中使用一个椭圆形表示用例。
用例在文档中需要详细说明,包括:
- 用例名称;
- 用例的参与者:使用该用例的参与者;
- 用例的进入条件:满足什么条件可以使用该用例;
- 用例的离开条件:满足什么条件可以结束该用例的使用;
- 流程:参与者使用该用例的步骤;
- 特殊需求:包含对用例性能上的需求或者拓展业务。
3️⃣关系:用例之间的关系只要包括三种,分别是扩展、包含和继承。
——扩展:扩展关系是在一个已有用例的基础上扩展新的功能而产生的关系,常用于对特殊情况的补充。比方说,购票“选票->付钱->出票->找零”本身是一个完整用例,但是在过程中可能出现零钱不足、缺票、用户中途取消等特殊状况,处理这些特殊状况的功能就是扩展功能。扩展功能在UML中用<>**和箭头表示,由子用例指向主用例。箭头的方向与主语->宾语一致。即 A extends B, 代表A扩展了B的功能,所以箭头由A指向B。
——包含:包含关系指一个主用例包含子用例。包含关系常用于子用例频繁被使用的情况。例如下图所示的例子,买单次票与买多次用卡的用例中都包含了收费这一子用例,为避免重复书写子用例,我们使用包含关系。
包含关系在UML中用**<>**和箭头表示,箭头指向由主用例指向子用例。箭头方向依然可以用语法判断,若A包含B,箭头方向就是A指向B。
——继承:处于继承关系中的用例在不同抽象层,其中被继承的一方是继承的一方更概括抽象的概念。例如:主用例是“用户识别”,“人脸识别”是用户识别的一种,“指纹识别”也是用户识别的一种。在继承关系中常常出现“…是…的一种”**(is a kind of)**这样的关系。
在UML中,继承关系由一个空心箭头表示,由继承的一方指向被继承的一方(具体的一方指向抽象的一方)。
在用例图中,用例关系的箭头方向是比较容易出错的一点,我的记忆方法是带入“A extends B”,“A includes B” 和 “A inherits B”这样的句型,箭头永远从主语指向宾语。
参与者:
用例:
关系
扩展:
包含:
继承:
活动图
活动图的作用是描述一系列具体动态过程的执行逻辑,展现活动和活动之间转移的控制流,并且它采用一种着重逻辑过程的方式来叙述。
主要包含元素:
1️⃣活动:表示工作流过程中命令的执行或活动的进行
2️⃣状态:一个活动图中只能有一个开始状态,但可以有多个终止状态或结束状态
3️⃣分支:活动的执行过程中,遇到需要判断的地方,则用菱形来表示,这也是流程产生分支的地方。
4️⃣同步条:
用于将一个控制流分为两个或多个并发运行的分支。亦或用于将两个或多个控制流合并到一起形成一个单向的控制流。一入多出,用于并行执行多个步骤5️⃣合并:多入一出,用于多个并行步骤汇集到同一流程
6️⃣执行顺序:
7️⃣泳道
时序图
时序图 Sequence Diagram是 UML 中最常见的交互图,通过描述对象间发送消息的时间顺序显示多个对象之间的动态协作状态。
数序图的元素稍多于用例图,有角色(Actors)、对象(Object)、生命线(Lifetime)、消息(Message)、激活(Focus of Control)等等。
1️⃣角色&&对象:
角色:通常指“人”,也可以是组织、机器、系统等等“抽象的人”,和用例图一样,用小人图表示
对象:就是与上述“人”对应的“物”了,包括所有产品、服务、设备等等抽象的物体
2️⃣生命线:
给每个角色和对象加上一条生命线。所谓的生命线就是从角色(或对象)引出向下延伸的虚线,表示时序图存在的时间轴。
3️⃣消息:消息自然是有来有往的,发送出去的消息叫 Request(请求),反馈的消息成为 Response(响应)
请求用实心箭头示意,并在箭头上方加注说明
响应用虚线箭头表示,也会加上简单的返回内容
4️⃣组合片段:组合片段用来解决交互执行中的条件反馈。
- 左上角黄色区域会标明片段的类型
- 片段中用虚线区分不同的条件子域
- 再在子域左上角——绿色阴影区——注释条件判断
- 最后在各自的条件子域上返回特定响应
5️⃣控制焦点:控制焦点又称激活,是覆盖在生命线上一段细长的矩形,表示在这个时间段内,对象或角色正处于活动状态;
通信图
通信图强调的是发送和接收消息的对象之间的组织结构,使用通信图来说明系统的动态情况。
通信图主要描述协作对象间的交互和链接,显示对象、对象间的链接以及对象间如何发送消息。
通信图可以表示类操作的实现
事物名称 | 解释 | 图 |
---|---|---|
参与者 | 发出主动操作的对象,负责发送初始消息,启动一 | |
对象 | 对象是类的实例,负责发送和接收消息,与顺序图中的符号相同,冒号前为对象名,冒号后为类名。 | |
消息流 | 箭头指示消息的流向,从消息的发出者指向接收者。 |
构件图
构件图用于静态建模,是表示构件类型的组织以及各种构件之间依赖关系的图。
构件图通过对构件间依赖关系的描述来估计对系统构件的修改给系统可能带来的影响
事物名称 | 含义 | 图例 |
---|---|---|
构件 | 指系统中可替换的物理部分,构件名字(如图中的Dictionary)标在矩形中,提供了一组接口的实现。 | |
接口 | 外部可访问到的服务 (如图中的Spellcheck)。 | |
接口实例 | 节点实例上的构件的一个实例,冒号后是该构件实例的名字(如图中的RoutingList)。 |
关系
关系名称 | 含义 | 图例 |
---|---|---|
实现关系 | 构件向外提供的服务 | |
依赖关系 | 构件依赖外部提供的服务(由构件到接口)。 |
状态机图
状态机图用于模拟各个类对象,用例和整个系统的动态行为。
1️⃣状态:表示对象的生命周期中的一种条件/情况,有初态和终态之分
2️⃣转换:表示两种状态间的一种关系
3️⃣事件:表示在某一时间与空间下所发生的有意义的事情
4️⃣动作:表示一个可执行的原子操作,是UML能够表达的最小计算单元
5️⃣活动:表示状态机中的非原子执行,一般由一系列动作组成
部署图
部署图描述的是系统运行时的结构,展示了系统的硬件配置、硬件部署,以及其软件如何部署到网络结构中(属于静态视图)。
1️⃣节点与节点实例:节点是存在与运行时的代表计算机资源的物理元素,可以是硬件也可以是运行其上的软件系统
节点:
节点实例:
2️⃣构件:构件是软件开发过程中的产物,包括过程模型(比如用例图、设计图等等)、源代码、可执行程序、设计文档、测试报告、需求原型、用户手册等等。
3️⃣连接: 节点之间的连线表示系统之间进行交互的通信路径,这个通信路径称为连接。
UML
UML类图需要暴露内部方法
1️⃣类:矩形表示
可见性
可见性 说明 + public - private # protected 2️⃣接口:与类相似,但是第一部分需要在接口名的上方加上 <> 修饰符。
3️⃣关系:共有六种关系,如下:
——继承关系(is a):由子类指向父类,即子类 -> 父类
——接口关系:由类指向接口,即类 -> 接口
——单项关联关系:单向关联指类 A 的内部拥有类 B,但类 B 的内部没有类 A
——双向关联关系:双向关联指类 A 的内部拥有类 B,并且类 B 的内部拥有类 A
——自关联:自关联指类 A 的内部拥有类 A(自己),它的符号和单向关联一样,不过它指向的是自己。例如在单链表中,每个节点内部都指向下一节点
——聚合关系(has a):聚合关系是单向关联的一种。在这种关系中,一般是整体对象拥有个体对象。
注意箭头方向是从被拥有对象指向大类,和关联关系相反
——组合关系(contains a):组合关系也是单向关联的一种。和聚合关系类似,一般是整体对象拥有个体对象。也就是说生命周期相同
箭头永远指向主语
——依赖关系:箭头指向被依赖方
比如说Employee类中有一个方法叫做TakeMoney(Bank bank)这个方法,在这个方法的参数中用到了Bank这个类。那么这个时候可以说Employee类依赖了Bank这个类,如果Bank这个类发生了变化那么会对Employee这个类造成影响。
包图
1️⃣包名:每个包必须有一个与其他包相区别的名称,包的名字是一个字符串,有简单名和路径名之分。
当不需要显示包的内容时,名字放在主方框
需要显示时,将包的名字放入左上角的小方框中,内容放入主方框内。
2️⃣包的可见性:用来表示包外界的元素对包内元素的可访问权限。
公有访问(+):表示包内的元素可以被任何引入了此包的其他包的内含元素访问。
保护访问(#):表示此元素能被该包的子包内所含元素访问。
私有访问(-):表示此元素只能被属于同一包的内含元素访问,外部无法访问。3️⃣包之间关系:依赖、泛化。
包之间的依赖关系实际上是从一个更高的层次来描述包内某些元素之间的依赖关系。也就是说,如果不同包中任何元素之间存在着一个依赖,则两个包之间就存在着依赖关系。
和类图中类之间的泛化关系是相似的
其他概念
适配器模式
我们有一个 MediaPlayer 接口和一个实现了 MediaPlayer 接口的实体类 AudioPlayer。默认情况下,AudioPlayer 可以播放 mp3 格式的音频文件。
我们还有另一个接口 AdvancedMediaPlayer 和实现了 AdvancedMediaPlayer 接口的实体类。该类可以播放 vlc 和 mp4 格式的文件。
我们想要让 AudioPlayer 播放其他格式的音频文件。为了实现这个功能,我们需要创建一个实现了 MediaPlayer 接口的适配器类 MediaAdapter,并使用 AdvancedMediaPlayer 对象来播放所需的格式。
AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,不需要知道能播放所需格式音频的实际类。AdapterPatternDemo 类使用 AudioPlayer 类来播放各种格式。
系统分析的十个原则
• 原理1:让系统用户参与
• 原理2:使用一套问题解决步骤
• 原理3:确定开发阶段与开发活动
• 原理4:在开发过程中记录文档
• 原理5:建立标准
• 原理6:管理过程与项目
• 原理8:不必害怕取消与返工
• 原理9:分而治之
• 原理10:设计系统时应考虑到增长和变化
内容太多,详见第三章PPT
5+2设计原则
1.单一职责原则
Single Responsibility Principle,SRP原则:一个类只负责一个功能领域中的相应职责。或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。单一职责原则是实现高内聚、低耦合的指导方针。
降低类的负责度,一个类只负责一项职责。
提高类的可读性,可维护性。
降低变更带来的风险。
2. 开放封闭原则
Open Closed Principle,OCP原则:需求改变时,在不改变软件实体源代码(类、接口、方法等)的前提下,通过扩展功能,使其满足新的需求。功能是开放的(功能提供方),代码修改是封闭的(功能使用方)。
用抽象构建框架,用实现扩展细节
参数类型、引用对象尽量使用接口或抽象类
抽象层尽量保持稳定:接口和抽象类只负责定义方法,但不负责具体实现
3. 里式替换原则
Liskov Substitution Principle,LSP原则:所有引用基类(父类)的地方必须能透明地使用其子类的对象。里氏代换原则表明,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立。该原则实际是在使用继承关系时的指导原则,遵循了该原则,那么采用继承时就不容易出错。
子类必须完全实现父类的抽象方法,但不能覆盖父类的非抽象方法
子类可以实现自己特有的方法
当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格‘
子类的实例可以替代任何父类的实例,但反之不成立
4.接口隔离原则
Interface Segragation Principle,ISP原则:客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。接口尽量细分,不要在一个接口中放很多方法。
接口分离原则和单一职责原则的关系:单一职责原则是为了高内聚,接口分离原则是为了低耦合。
5.依赖倒置原则
Dependence Inversion Principle,DIP原则:
高层模块不应该依赖底层模块,二者都应该依赖其抽象(接口)。
抽象不应该依赖细节,细节应该依赖抽象。
依赖倒置的本质是通过抽象(接口或抽象类)是各个类或模块的实现彼此独立,互不影响,实现模块间的低耦合。相对于细节的多变性,抽象的东西要稳定的多。应用依赖倒置的设计模式:工厂方法。
依赖注入的三种方式:
- 接口注入:在接口/类中,将要注入的服务对象,以参数的形式直接注入
- 构造方法注入:通过构造函数来传入具体类的对象
- set方法注入:通过Setter方法来传入具体类的对象
6.合成复用原则
尽量使用对象聚合/ 组合,而不是继承来达到复用的目的。
组合是一种较为紧密的关系,从生命周期上看,部分和整体是共存亡的关系。 聚合则是一种较为松散的关系,部分和整体的生命周期未必一致
继承复用:
- 优点:简单,容易实现
- 缺点:破坏了封装性,耦合度高,限制灵活性
合成复用:
- 优点:维持封装性,降低耦合度,灵活性高
- 缺点:有较多的对象需要管理
7.迪米特原则
The Least Knowledge Principe,/Demeter Principle:它要求一个对象应该对其他对象有最少的了解(最少知识原则),降低类之间的耦合。迪米特原则实际上就是一个类在创建方法和属性时要遵守的法则。
迪米特法则还有一种定义形式:不要和“陌生人”说话,只与你的直接朋友通信等。在迪米特法则中,对于一个对象,其“朋友”包括以下几类:
当前对象本身(this);
以参数形式传入到当前对象方法中的对象;
当前对象的成员对象;
如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;
当前对象所创建的对象。
遵循迪米特原则的设计模式:
门面模式
中介模式
MVC
MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。
- Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
- View(视图) - 视图代表模型包含的数据的可视化。
- Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
实现
我们将创建一个作为模型的 Student 对象。StudentView 是一个把学生详细信息输出到控制台的视图类,StudentController 是负责存储数据到 Student 对象中的控制器类,并相应地更新视图 StudentView。
MVCPatternDemo,我们的演示类使用 StudentController 来演示 MVC 模式的用法。
Contoller就是Spring MVC里的Controller,不处理业务逻辑
Model就是业务逻辑与数据库交互的部分
View就是调用接口的前端页面
范式:
1NF:
1NF 的定义要求数据库表中的每一列都是不可拆分的原子值,即每个单元格中的数据都是不可再分的基本数据单元
2NF:
举例说明
学号 | 课程号 | 成绩 |
---|---|---|
上面的表,基本上是满足第二范式的。
学号 | 课程号 | 成绩 | 姓名 | 课程名 |
---|---|---|---|---|
这里明显,主键是"学号+课程号",“成绩"依赖于"主键”(学号+课程号→成绩),但是"姓名"只依赖于"学号"(学号→姓名),“课程名"只依赖于"课程号”(课程号→课程名),所以这里,不满足第二范式了。
那么这里“姓名”和"课程号"对于主键来说是非完全依赖。
关于第二范式的函数依赖关系分析结果如下表。
Y | 1X’ | 2X’ | X | 数学表达 | 文字表达-函数依赖 |
---|---|---|---|---|---|
3NF
举例说明
定义:如果一个关系属于2NF,且每个非关键字不传递依赖于主关键字,这种关系是3NF。
假定学生关系表为Student(学号, 姓名, 年龄, 所在学院, 学院地点, 学院电话),关键字为单一关键字"学号",因为存在如下决定关系:
(学号) → (姓名, 年龄, 所在学院, 学院地点, 学院电话)
这个数据库是符合2NF的,但是不符合3NF,因为存在如下决定关系:
(学号) → (所在学院) → (学院地点, 学院电话)
即存在非关键字段"学院地点"、"学院电话"对关键字段"学号"的传递函数依赖。
它也会存在数据冗余、更新异常、插入异常和删除异常的情况,读者可自行分析得知。
把学生关系表分为如下两个表:
学生:(学号, 姓名, 年龄, 所在学院);
学院:(学院, 地点, 电话)。
静态动态图
静态模型元素
-
类图(Class Diagram): 类图是描述系统中的类、接口、关系和类成员等静态结构的主要图表。它显示了系统中对象之间的静态关系。
-
对象图(Object Diagram): 对象图是类图的实例,它显示了在特定时间点系统中对象的实例及其关系。
-
包图(Package Diagram): 包图用于组织和管理系统中的元素,将其分组到包中,以便更好地管理复杂性。
-
部署图(Deployment Diagram): 部署图描述了系统中的物理部署,包括硬件节点、软件节点以及它们之间的连接。
-
构件图
动态模型元素:
-
用例图(Use Case Diagram): 用例图描述了系统的功能需求,其中包括用户(或外部实体)与系统之间的交互。
-
活动图(Activity Diagram): 活动图显示了系统中各种活动的流程和控制流,通常用于描述业务流程或操作的动态行为。
-
状态图(State Diagram): 状态图描述了对象在其生命周期内的状态以及状态之间的转换条件。
-
时序图(Sequence Diagram): 时序图描述了对象之间的交互顺序,特别是在特定时间内消息的发送和接收。
-
通信图