返回

软件设计师(转载自用)

来源:bilibili zst_2001

Table of contents

Open Table of contents

基础知识

第一章 计算机系统

计算机系统基础知识

计算机系统硬件基本组成

计算器的基本硬件系统由运算器、控制器、存储器、输入设备、输出设备的 5 大部件组成。

中央处理单元

中央处理单元(CPU)是计算机系统的核心部件,它负责获取程序指令、对指令进行译码并加以执行。

1. CPU 的功能
2. CPU 的组成

CPU 主要由运算器、控制器、寄存器组和内部总线等部件组成。

  1. 运算器:运算器只能完成运算。

    • 算术逻辑单元(ALU):负责处理数据,实现对数据的算数运算和逻辑运算
    • 累加寄存器(AC):运算器的算数逻辑单元执行算数或逻辑运算时,为 ALU 提供一个工作区,运算的结果存储在 AC 中。
    • 数据缓冲寄存器(DR):作为 CPU 和内存、外部设备之间的中转站。
    • 状态条件寄存器(PSW):保存各种条形码内容。
  2. 控制器:控制器用于控制整个 CPU 的工作,它决定了计算机运行过程的自动化。它不仅要保证程序的正确执行,而且要能够处理异常事件。

    • 指令寄存器(IR):当 CPU 执行指令时,先把它从内存存储器取到缓冲寄存器中,在送入 IR 暂存。对用户完全透明
    • 程序计数器(指令计数器)(PC):跟踪指令的地址。PC 在顺序执行的时候加 1,在转移执行的时候加上一个位移量
    • 地址寄存器(AR):保存当前 CPU 所访问的内存单元的地址
    • 指令译码器(ID):指令包含操作码和地址码。对指令中的操作码进行分析解释
    • CPU基本组成

补充:指令 == 操作码 + 地址码

计算机基本单位

位(比特) 最小数据单位bit、b8b=1B
字节 最小存储单位byte、B1B = 8b
千字节KB1KB = 1024B
兆字节MB1MB = 1024KB
吉字节GB1GB = 1024MB
太字节TB1TB = 1024GB

数据表示

进制英文简写
二进制B
八进制O
十进制D
十六进制H

各种码制带符号数的范围

带符号数的范围

浮点数

浮点数使用两个定点数来分别表示实数的尾数(F)和阶码(E)。其一般形式为:N = 2^E * F

image

寻址

校验码

  1. 奇偶校验码
    • 只能检错,不能纠错,码距 = 2。
    • 只能检测出奇数个数据位出错,不能检测偶数个数据位出错
    • 水平奇偶校验码、垂直奇偶校验码、水平垂直奇偶校验码。
  2. 海明码
    • 海明码可以检错也可以纠错。
    • 码距 = 2 ,检错能力     码距 >= 3,才有可能有纠错能力
    • 数据位是 n,校验位是 k,则 n 和 k 必须满足一下关系: 2^*k* − 1≥ *n*+k
  3. 循环冗余校验码(CRC)
    • 可以检错,但不能纠错,码距 = 2。
    • k 个数据位后跟 r 个校验位
    • 校验位 r 采用模 2 运算

计算机体系结构

CISC 和 RISC

RISC 精简指令集计算机CISC 复杂指令集计算机
指令种类少、精简多、丰富
指令复杂度低(简单)高(复杂)
指令长度固定变化
寻址方式复杂多样
实现(译码)方式硬布线控制逻辑(组合逻辑控制器)微程序控制技术
通用寄存器数量多、大量一般
流水线技术支持不支持

流水线

计算机中的流水线技术是把一个重复的过程分解为若干个子过程,每个子过程与其他子过程并行进行。

若要执行 n 条指令:

存储系统

  1. SRAM(静态随机存储器):构成 Cache(缓存)
  2. DRAM(动态随机存储器):构成主存 DRAM 需要周期性地刷新保持信息。
  3. RAM(读/写存储器)
  4. ROM(只读存储器)
  5. PROM(可编程的只读存储器)

Cache 存储器部分用来存放主存的部分拷贝(副本)信息。控制部分的功能是判断 CPU 要访问的信息是否在 Cache 存储器中,若在即为命中,若不在则没有命中。命中时直接对 Cache 存储器寻址;未命中时,要按照替换原则决定主存的一块信息放到 Cache 存储器的哪一块里。

中断

计算机在执行程序过程中,当遇到急需处理的事件时,暂停当前正在运行的程序,转去执行有关服务程序,处理完后自动返回源程序,这个过程称为中断。

输入输出(I/O)控制方式

  1. 程序查询方式
    • CPU 和 I/O(外设)只能串行工作 ,CPU 需要一直轮询检查,长期处于忙等状态。CPU 利用率低
      • 一次只能读/写一个字
      • 由 CPU 将数放入内存
      • image
  2. 中断驱动方式
    • I/O 设备通过中断信号主动向 CPU 报告 I/O 操作已完成
      • CPU 和 I/O(外设)可并行工作
      • CPU 利用率得到提升
      • 一次只能 读/写 一个字
      • 由 CPU 将数据放入内存
      • image
  3. 直接存储器方式(DMA)
    • CPU 和 I/O(外设)可并行工作
    • 仅在传送数据块的开始和结束时才需要 CPU 的干预
    • 由外设直接将数据放入内存
    • 一次读写的单位为”块“而不是字
    • image

总线

总线是连接计算机有关部件的一组信号线,是计算机中用来传送信息代码的公共通道。

采用总线结构主要有以下优点:

在计算机系统中采用总线结构,便于实现系统的积木化构造,同时可以减少信息传输线的数量。

微机中的总线分为:

常见总线:

加密技术和认证技术

加密算法

对称密钥(私钥、私有密钥加密)算法(共享密钥加密算法)非对称密钥(公钥、公开密钥加密)算法
DESRSA
3DESECC
RC-5DSA
IDEA
AES
RC4

Hash 函数

MD5 摘要算法(128 位散列值)

SHA-1 安全散列算法

认证是处理主动攻击

可靠性

  1. 串联系统。假设一个系统由 N 个子系统组成,当且仅当所有子系统都能正常工作时系统才能正常工作,这样的系统称为串联系统。
    • image
    • 系统可靠性 R = R₁R₂···Rn
  2. 并联系统。假设一个系统由 N 个子系统组成,只要有一个子系统正常工作,系统就能正常工作,这样的系统称为并联系统。
    1. image
    2. 系统可靠性 R = 1 - (1-R₁)(1-R₂)···(1-Rn)

补充列题说明

XY逻辑与逻辑或逻辑异或逻辑同或
000001
010110
100110
111101

第二章 程序设计语言

程序设计语言的基本概念

程序设计语言的基本成分

函数定义

函数的定义包括两部分:函数首部和函数体。函数的定义描述了函数做什么和怎么做。

函数定义的一般形式为:

返回值的类型 函数名(形式参数表) //函数首部 函数名(实参表);
{
 ​ 函数体;
 }

(1)值调用。若实现函数调用时将实参的值传递给相应的形参, 则称为是传值调用。在这种方式下形参不能向实参传递信息。

(2)引用调用。引用是 C++ 中引入的概念,当形式参数为引用类型时,形参名实际上是实参的别名,函数中对形参的访问和修改实际上就是针对相应实参所做的访问和改变。

编译程序基本原理

image

符号表:不断收集、记录和使用源程序中一些相关符号的类型和特征等信息,并将其存入符号表中。记录源程序中各个字符的必要信息,以辅助语义的正确性检查和代码生成。

1)词法分析

输入:源程序

输出:记号流

词法分析阶段的主要作用是:分析构成程序的字符及由字符按照构造规则构成的符号,是否符合程序语言的规定

2)语法分析

输入:记号流

输出:语法树(分析树)

语法分析阶段的主要作用是:对各条语句的结构进行合法性分析,分析程序中的句子结构是否正确。

3)语义分析

输入:语法树(分析树)

语义分析阶段的主要作用是进行类型分析和检查

语义分析阶段可以发现程序中所有的语法错误

语义分析阶段不能发现程序中所有的语义错误

语义分析阶段可以发现静态语义错误,不能发现动态语义错误,动态语义错误运行时才能发现(eg:除数为 0 时只能在运行阶段检查出来)

4)中间代码生成

常见的中间代码有:后缀式、三地址码、三元式、四元式和树(图)等形式。

中间代码与具体的机器无关(不依赖具体的机器),可以将不同的高级程序语言翻译成同一种中间代码。

中间代码可以跨平台。

因为与具体的机器无关,使用中间代码有利于进行与机器无关的优化处理和提高编译程序的可移植性。

6)目标代码生成

目标代码生成阶段的工作与具体的机器密切相关

寄存器的分配工作处于目标代码生成阶段

正规式

image

有限自动机

上下文无关文法

中缀后缀表达式

中缀式:a ? b ===> 后缀式:ab? 后缀式转中缀式可以用:栈

+-*/ 的优先级和数学一致,优先级相同,从右向左

中间代码有多种形式,其中树与后缀表示形式适用于解释器,而编译器多采用与机器指令格式较接近的四元式形式。

根据生成的语法树,按照不同的方式遍历即可生成形式不同的表达式:

逆波兰式其实就是后缀式。

第三章 数据结构

这章我没怎么看,大家自己补充一下

第四章 操作系统

概述

计算机系统由两部分组成:

通常把未配置软件的计算机称为裸机。

操作系统目的是:为了填补人与机器之间的鸿沟,即建立用户与计算机之间的接口,而为裸机配置的一种系统软件。

操作系统也包括了系统软件。

操作系统在计算机系统中的地位:

image

操作系统是用户与计算机之间的接口,它在计算机系统中占据重要而特殊的地位,所有其他软件,如编辑程序、汇编程序、编译程序、数据库管理系统等系统软件,以及大量的应用软件都是建立在操作系统基础上的,并得到它的支持和取得它的服务。

程序与进程

程序顺序执行时的主要特征包括:顺序性、封闭性和可再现性。

程序并发执行时的主要特征包括:失去了程序的封闭性、程序和机器的执行程序的活动不再一一对应、并发程序之间的相互制约性。

三态模型

在多道程序系统中,进程在处理器上交替运行,状态也不断地发生变化,因此进程一般有 3 种基本状态:运行、就绪和阻塞。

image

进程CPU资源
运行
就绪×
阻塞××

进程间的通信

在多道程序环境的系统中存在多个可以并发执行的进程,故进程间必然存在资源共享和相互合作的问题。进程通信是指各个进程交换信息的过程。

同步和互斥

临界区管理的原则:

临界区:是进程中对临界资源实施操作的那段程序。

对互斥临界区管理的 4 条原则如下:

信号量机制

信号量机制是一种有效的进程同步与互斥工具。

信号量机制主要有:

整型信号量:

信号量是一个整型变量,根据控制对象的不同被赋予不同的值。信号量分为如下两类:

信号量 S 的物理意义:

PV 操作

PV 操作:实现进程同步与互斥的常用方法。

P 操作和 V 操作是低级通信原语,在执行期间不可分割。其中:

P 减 V 加,P 进 V 出。

利用 PV 操作实现进程的互斥:

  1. 令信号量mutex的初始值为 1;
  2. 进入临界区:执行 P 操作;
  3. 推出临界区:执行 V 操作。

利用 PV 操作实现进程的同步:

实现进程的同步可用一个信号量与消息联系起来。

信号量的值:

假定信号量 S 表示某条消息,进程可以:

死锁

当有 n 个进程,m 个资源,且每个进程所需要的资源数为 k,并且系统采用的分配策略是轮流地为每个进程分配资源时,判断是否发生死锁的公式如下:

m >= n * (k-1)+1

死锁的处理策略主要有 4 种:鸵鸟策略(即不理睬策略)、预防策略、避免策略和检测与解除死锁。

进程资源图

做题方法:先分配,再申请

线程

传统进程有两个基本属性:

  • 可拥有资源的独立单位;
  • 可独立调度和分配的基本单位。

引入线程的原因是,进程的系统必须付出较大的时空开销。引入线程后,将传统进程的两个基本属性分开:

线程是进程中的一个实体,是被系统独立分配和调度的基本单位。

线程的特点:

线程因其具有许多传统进程所具有的特性,故称为”轻型进程”;而传统进程称为”重型进程”。

线程分为:

某些系统同时实现了两种类型的线程。

与线程不同的是,不论是系统进程还是用户进程,在进行切换时,都要依赖于内核中的进程调度。因此,不论是什么进程都是与内核有关的,是在内核支持下进行切换的。

存储管理

程序局部性原理

程序在执行时将呈现出局部性规律,即在一段时间内,程序的执行仅局限于某个部分。相应地,它所访问的存储空间也局限于某个区域内。

程序的局限性表现在以下两个方面:

分页存储管理

分页原理:

在为进程分配主存时,将进程中若干页分别装入多个不相邻接的块中。

地址结构:

image

其中,页内地址是同一页(页号)中的偏移量。

分页的过程是由操作系统完成的,对用户是透明的,所以用户不必关心分页的过程,其优点是能有效地提高主存利用率,其缺点是不易实现共享。

段页式存储管理

结合分页和分段存储管理方式,形成一种新的存储管理方式,即段页式存储管理。段页式系统有两种系统的优点。

段页式系统的基本原理是:

  1. 将整个主存划分成大小相等的存储块(页框)。
  2. 将用户程序按程序的逻辑关系分为若干个段,并为每个段赋予一个段名。
  3. 将每个段划分成若干页,以页框为单位离散分配。

段页式地址空间的结构:

image

设备管理

缓冲技术

缓冲技术可提高外设利用率,尽可能使外设处于忙状态。缓冲技术可以采用两种方式:

单缓冲

单缓冲工作过程图:

image

当第 1 块数据送入用户工作区后(进行数据处理),缓冲区是空闲的,可以传送第 2 块数据(输入)。即第 1 块数据的处理 C1 与第 2 块数据的输入 T2 是可以并行的,以此类推:

image

(前提是 c 要小于 T)计算公式为:(T + M)* n + c

磁盘调度算法

总结:

  1. 先来先服务(FCFS) :根据进程请求访问磁盘的先后次序进行调度。
  2. 最短寻道时间优先(SSTF):该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,使得每次的寻道时间最短。
  3. 扫描算法/电梯调度算法(SCAN):扫描算法不仅考虑到要访问的磁道与当前磁道的距离,更优先考虑的是磁头的当前移动方向。
  4. 单向扫描调度算法(CSCAN):为了减少这种延迟,算法规定磁头只做单向移动。

文件管理

双缓冲

双缓冲进一步加快 I/O 的速度,提高了设备的利用率。其工作基本过程是在设备输入时,先将数据输入到缓冲区 1,装满后便转向缓冲 2。

双缓冲工作过程图:

image

双缓冲的工作特点是,可以实现对缓冲中数据的输入 T 和提取 M,与 CPU 的计算 C,三者并行工作:

image

(前提是 M +c < T)计算公式为:T * n + M + c

多级索引结构

image

文件目录

文件控制块

文件控制块中包含以下信息:

目录结构

组织好文件的目录是设计文件系统的重要环节,文件目录结构的组织方式直接影响到文件的存取速度,关系到文件的共享性和安全性。

常见的目录结构有:

位示图

位示图是一种空闲空间管理方法。通过在外存上建立一张位示图,记录文件存储器的使用情况。

位示图用二进制的一位来表示一个物理块的使用情况:

例如:

image

位示图的大小由磁盘空间的大小(物理块总数)决定。

位示图的描述能力强,适合各种物理结构。

做题技巧:

第五章 软件工程

软件过程

1. 能力成熟度模型(CMM)

CMM 将软件过程改进分为以下 5 个成熟度级别:

1)初始级(最低成熟度)

软件过程的特点是杂乱无章,有时甚至很混乱,几乎没有明确定义的步骤,项目的成功完全依赖个人的努力和英雄式核心人物的作用。

2)可重复级

建立了基本的项目管理过程和实践来跟踪项目费用、进度和功能特性,有必要的过程准则来重复以前在同类项目中的成功。

3)已定义级

管理和工程两方面的软件过程已经文档化、标准化,并综合成整个软件开发组织的标准软件过程

4)已管理级

制定了软件过程和产品质量的详细度量标准。软件过程的产品质量都被开发组织的成员所理解和控制。

5)优化级(最高成熟度)

加强了定量分析,通过来自过程质量反馈和来自新观念、新技术的反馈使过程能不断持续地改进。

2. 能力成熟度模型集成(CMMI)

CMMI 提供了两种表示方法:

1)阶段式模型

阶段式模型的结构类似于 CMM,它关注组织的成熟度。

有五个成熟度等级:

2)连续式模型

连续式模型关注每个过程域的能力,一个组织对不同的过程域可以达到不同的过程域能力。

CMMI 中包括 6 个过程域能力等级:

软件过程模型

软件开发过程模型是指为了有效地开发、维护和更新软件系统,提出的一系列步骤、阶段和方法的系统框架,以实现提高软件质量、加快开发速度和降低开发成本的目的。

常见的软件开发过程模型包括瀑布模型、增量模型、演化模型(原型模型、螺旋模型)和喷泉模型。

瀑布模型

瀑布模型是一种线性的软件开发过程模型,开发流程严格按照顺序依次进行,每个阶段都必须完成后才能进入下一个阶段。瀑布模型包括需求分析、设计、编码、测试和维护五个阶段。

瀑布模型:

瀑布模式适合用于:

增量模型

增量模型采用了逐步完善的思路,将软件的开发过程划分为一个个的增量,每个增量都能够独立实现某一或多项功能或特性。在逐步实现的过程中,可以不断根据需求变化来进行迭代,从而保证最终的软件达到客户需求和期望。

增量模型作为瀑布模型的一个变体,具有瀑布模型的所有优点。此外,它还有以下优点:

缺点:

量模型适合用于:

演化模型

演化模型是迭代的过程模型,使得软件开发人员能够逐步开发出更完整的软件版本。演化模型特别适用于对软件需求缺乏准确认识的情况。典型的演化模型有原型模型和螺旋模型等。

原型模型

并非所有的需求都能够预先定义。大量的实践表明,在开发初期很难得到一个完整的、准确的需求规格说明。原因有:

原型模型:

原型的目的是能快速、低成本地构建原型系统。

能够采用原型方法是因为开发工具的快速发展,使得能够迅速地开发出一个让用户看得见、摸得着的系统框架。这样,对于计算机不是很熟悉的用户就可以根据这个框架提出自己的需求。

开发原型系统首先确定用户需求,开发初始原型,然后征求用户对初始原型的改进意见,并根据意见修改原型:

image

  1. 交流:目的是定义软件的总体目标,标识需求,然后
  2. 快速计划:快速制订原型开发的计划,确定原型的目标和范围
  3. 采用快速设计方式进行建模
  4. 构建原型
  5. 部署交付和反馈:被开发的原型应交付给客户使用,并收集客户的反馈意见,这些反馈意见可在下一轮中对原型进行改进
  6. 下一轮迭代:在前一个原型需要改进,或者需要扩展其范围的时候,进入下一轮原型的迭代开发

根据使用原型的目的不同,原型可以分为:

螺旋模型

对于复杂的大型软件,开发一个原型往往达不到要求。

螺旋模型将瀑布模型和演化模型结合起来,加入了两种模型均忽略的风险分析(以风险为驱动),弥补了这两种模型的不足。

螺旋模型将开发过程分为几个螺旋周期,每个螺旋周期大致和瀑布模型相符合:

image

螺旋模型属于面向对象开发模型。

螺旋模型适用于:

优点:

缺点:

喷泉模型

喷泉模型:喷泉模型克服了瀑布模型不支持软件重用和多项开发活动集成的局限性

泉模型使开发过程具有以下性质或特点:

优点:可以提高软件项目的开发效率,节省开发时间。

缺点:

统一过程(UP)模型

阶段里程碑关注产生
初始阶段生命周期目标项目的初创活动构想文档、业务用例、项目计划、风险评估
精化阶段生命周期架构需求分析和架构演进补充需求分析、软件架构描述、架构原型制品
构建阶段初始运作功能系统的构建具有最初运作能力的软件产品
移交阶段产品发布软件提交方面的工作产品发布版本

敏捷方法

敏捷方法是一种反应灵活、拥有高度互动性和以人为本的软件开发方法。它的核心是通过不断地交付成果和及时反馈,来满足客户需求和不断变化的业务环境。以下是敏捷方法中的一些常见实践:

极限编程(XP)

极限编程是为了降低需求变更所带来的成本,旨在提高软件质量和对客户需求变化的适应性,期望能够让软件开发达到低成本、低缺陷、高产出、高回报(最小投入得到最大结果)的效果。

极限编程(XP)软件开发方式有以下性质:

XP 由价值观、原则、实践和行为 4 个部分组成,他们之间彼此相互依赖、关联,并通过行为贯穿于整个生存周期:

水晶法(Crystal)

并列争求法(Scrum)

使用迭代的方法。

自适应软件开发(ASD)

有 6 个基本原则:

敏捷统一过程(AUP)

敏捷统一过程采用以下原理来构建软件系统:

采用经典的 UP 阶段性活动(初始、精化、构建和转换),提供了一系列活动,能够使团队为软件项目构想出一个全面的过程流。

在每个活动里,一个团队迭代使用敏捷,并将有意义的软件增量尽可能快地交付给最终用户。每个 AUP 迭代执行以下活动:

软件需求

软件需求是指用户对目标软件系统在功能、行为、性能、设计约束等方面的期望。通常,这些需求包括:

软件需求的出处:

系统设计

概要设计

  1. 设计软件系统总体结构

    • 确定每个模块的功能
    • 确定模块之间的调用关系
    • 确定模块之间的接口
  2. 数据结构及数据库设计

  3. 编写概要设计文档

  4. 评审

详细设计

  1. 对每个模块进行详细的算法设计
  2. 对模块内的数据结构进行设计
  3. 对数据库进行物理设计
  4. 其他设计
    1. 代码设计
    2. 输入输出格式设计
    3. 用户界面设计
  5. 编写详细设计说明书
  6. 评审

编码

根据详细设计进行代码的编写,得到可以运行的软件,并进行单元测试。

系统测试

意义:系统测试是为了发现错误而执行程序的过程,成功的测试是发现了至今尚未发现的错误的测试。 目的:测试的目的就是希望能以最少的人力和时间发现潜在的各种错误和缺陷。

系统测试原则

  1. 应尽早并不断地进行测试。
  2. 测试工作应该避免由原开发软件的人或小组承担。
  3. 在设计测试方案时,不仅要确定输入数据,而且要根据系统功能确定预期输出结果。
  4. 在设计测试用例时,不仅要设计有效、合理的输入条件,也要包含不合理、失效的输入条件。
  5. 在测试程序时,不仅要检验程序是否做了该做的事,还要校验程序是否做了不该做的事。
  6. 严格按照测试计划来进行,避免测试的随意性。
  7. 妥善保存测试计划、测试用例。
  8. 测试用例都是精心设计出来的。
  9. 系统测试阶段的测试目标来自于需求分析阶段。

单元测试(模块测试)

  1. 单元测试的测试内容

    • 模块接口
      • 测试模块的输入参数和形式参数在个数、属性、单位上是否一致。
      • 调用其他模块时,所给出的实际参数和被调用模块的形式参数在个数、属性、单位上是否一致。
      • 调用标准函数时,所用的参数在属性、数目和顺序上是否正确。
      • 全局变量在各模块中的定义和用法是否一致。
      • 输入是否仅改变了形式参数。
      • 开/关的语句是否正确。
      • 规定的 I/O 格式是否与输入/输出语句一致。
      • 在使用文件之前是否已经打开文件或使用文件之后是否己经关闭文件。
    • 局部数据结构
    • 重要的执行路径
    • 出错处理
    • 边界条件
  2. 单元测试过程

    • 驱动模块:接收测试例子的数据,将这些数据送到测试模块,输出结果。即模拟被测试模块的上一级模块,相当于被测模块的主程序。
    • 桩模块:代替测试模块中所调用的子模块,其内部可进行少量的数据处理。目的是为了检验入口、输出调用和返回的信息。
    • 提高模块的内聚度可以简化单元测试。

集成测试

集成测试是进行一些旨在发现与接口相关的错误的测试,其目标是利用已通过单元测试的构件建立设计中描述的程序结构。

  1. 自顶向下集成测试

​ 自顶向下集成测试是一种构造软件体系结构的增量方法。

自顶向下集成不需要驱动模块,需要桩模块。

  1. 自底向上集成测试

​ 自底向上集成测试就是从原子模块(程序结构的最底层构件)开始进行构造和测试。

自底向上集成需要驱动模块,不需要桩模块。

  1. 回归测试:重新执行己测试过的某些子集,以确保变更没有传播不期望的副作用。
  2. 冒烟测试:一种常用的集成测试方法,是时间关键项目的决定性机制,它让软件团队频繁地对项目进行评估。

测试方法

测试方法分为:

黑盒测试(功能测试)

黑盒测试在完全不考虑软件的内部结构和特性的情况下,测试软件的外部特性

McCabe 度量法(边 - 节 + 2)

image

白盒测试(结构测试)

白盒测试根据程序的内部结构和逻辑来设计测试用例,对程序的路径和过程进行测试,检查是否满足设计的需要。

白盒测试逻辑覆盖技术总结(覆盖程度从低到高):

逻辑覆盖说明
语句覆盖每条语句执行一次
分支(判定)覆盖每个分支获得一次 True/False
条件覆盖每个分支中的每个逻辑条件的所有可能取值满足一次
判定/条件覆盖分支覆盖 + 条件覆盖
条件组合覆盖每个判定中条件的各种可能值的组合都出现一次
路径覆盖覆盖被测试程序中所有可能的路径

运行和维护

系统可维护性概念

系统是否能被很好地维护,可以用系统的可维护性这一指标来衡量。

系统可维护性的评价指标

软件文档与软件维护

软件文档是软件可维护性的决定因素。文档是软件产品的一部分,并且编写高质量的文档可以提高软件开发的质量。

软件系统的文档分为:

可维护性是所有软件都应具有的基本特点,必须在开发阶段保证软件具有可维护的特点。在软件工程的每一个阶段都应考虑并提高软件的可维护性,在每个阶段结束前的技术审查和管理复查中应该着重对可维护性进行复审(如将来要改进的部分和可能会修改的部分)。

做题技巧:

系统维护的内容及类型

软件维护:

软件可靠性、可用性、可维护性

项目管理

沟通路径

沟通图是指项目中人员或部门之间的沟通用一条无向边连接起来,所构成图即为沟通图。沟通图中的路径称为沟通路径。

软件项目中沟通路径 m 的计算公式(人数 n):

COCOMO 估算模型

COCOMO 模型是一种精确的、易于使用的成本估算模型。COCOMO 模型按其详细程度分为:

  1. 基本 COCOMO 模型:是一个静态单变量模型,用于对整个软件系统进行估算。
  2. 中级 COCOMO 模型:是一个静态多变量模型,它将软件系统模型分为系统和部件两个层次,系统由部件构成,它把软件开发所需的人力(成本)看作是程序大小和一系列“成本驱动属性”的函数。
  3. 详细 COCOMO 模型:将软件系统模型分为系统、子系统和模块 3 个层次,除包括中级模型所考虑的因素外,还考虑了在需求分析、软件设计等每一步的成本驱动属性的影响。

COCOMOII 模型

和其前身 COCOMO 一样,COCOMOII 也是一种层次结构的估算模型,被分为 3 个阶段性模型,分别对应三种不同的规模估算选择:

  1. 应用组装模型:在软件工程的前期阶段使用,这时用户界面的原型开发、对软件和系统交互的考虑、性能的评估以及技术成熟度的评价是最重要的。

    规模估算选择:对象点

  2. 早期设计阶段模型:在需求己经稳定并且基本的软件体系结构己经建立时使用。

    规模估算选择:功能点。功能点可转换为代码行。

  3. 体系结构阶段模型:在软件的构造过程中使用。

    规模估算选择:代码行

进度管理

Gantt 图

PERT 图

PERT 图是一个有向图:

PERT 图的优点:

PERT 图不能清晰地描述任务之间的并行情况。

项目活动图

项目活动图是一种有向图(与 PERT 图十分类似):

项目活动图的关键路径:按照 PERT 图的方法求出松弛时间为 0 的、从开始里程碑到结束里程碑的路径。

关键路径的长度:为结束里程碑的最早时刻(或最晚时刻)。它可以用来表示项目完成的最少时间。

软件配置管理

软件配置管理的主要目标包括:

主要内容有两种版本:

    • 版本管理
    • 配置支持
    • 变更支持
    • 过程支持
    • 团队支持
    • 变化报告
    • 审计支持
    • 软件配置标识
    • 变更管理
    • 版本控制
    • 系统建立
    • 配置审核
    • 配置状态报告

配置数据库分为以下三类:

风险管理

一般认为软件风险包含两个特性:

项目风险威胁到项目计划。项目风险是指以下各方面的潜在问题以及它们对软件项目的影响:

以下方面的不确定性也属于项目风险因素:

技术风险威胁到要开发软件的质量及交付时间。技术风险是指以下方面的潜在问题:

商业风险威肋到要开发软件的生存能力,且常常会危害到项目或产品。5 个主要的商业风险如下:

风险识别

风险识别试图系统化地指出对项目计划(估算、进度、资源分配等)的威胁。识别出已知风险和可预测风险后,项目管理者首先要做的是:

识别风险的一种方法是建立风险条目检查表(未考察),主要用来识别下列几种类型中的一些已知风险和可预测风险:

与上述每个主题相关的问题可以针对每一个软件项目来回答。根据这些问题的答案,项目管理者就可以估计风险产生的影响。另一种风险条目检查表格式:仅仅列出与每一种类型有关的特性,最终给出一组风险因素和驱动因子以及它们发生的概率。

风险因素(未考察)包括:

风险预测

风险预测又称风险估计,它试图从两个方面评估一个风险:

通常,项日计划人员与管理人员、技术人员一起进行以下 4 步风险预测活动:

  1. 建立一个尺度或标准,以反映风险发生的可能性。
  2. 描述风险产生的后果。
  3. 估算风险对项目和产品的影响。
  4. 标注风险预测的整体精确度,以免产生误解。

一种简单的风险预测技术是建立风险表:

评估风险影响:发生风险时,有 3 个因素可能会影响风险所产生的后果:

风险评估

一种对风险评估很有用的技术就是定义风险参照水准。对于大多数软件项目来说,有 3 种典型的风险参照水准

风险控制

风险控制的目的是辅助项目组建立处理风险的策略。一个有效的策略必须考虑以下 3 个问题:

软件质量

软件质量特性

讨论软件质量首先要了解软件的质量特性,目前己经有多种软件质量模型来描述软件质量特性,如:

ISO/IEC 9126

ISO/IEC 9126 软件质量模型由 3 个层次组成:

  1. 第一层:质量特性
  2. 第二层:质量子特性
  3. 第三层:度量指标

image

质量子特性的含义:

简单记忆:

功能性可靠性易用性效率可维护性可移植性
适合、安全、准、互、依成、容、恢理、学、操时、资分、改、稳、测适应、安装、一、替

Mc Call 软件质量模型

Mc Call 也给出了一个三层模型框架:

  1. 第一层:质量特性
  2. 第二层:评价准则
  3. 第三层:度量指标

image

软件评审

通常,把“质量”理解为“用户满意程度”。为了使得用户满意,有以下两个必要条件:

软件的规格说明分为:

软件容错技术

提高软件质量和可靠性的技术大致可分为两类:

实现容错的主要手段是冗余。冗余是指对于实现系统规定功能是多余的那部分资源,包括:

由于加入了这些资源,有可能使系统的可靠性得到较大的提高。通常,冗余技术分为 4 类:

软件工具

软件开发工具

对应于软件开发过程的各种活动,软件开发工具通常有:

软件维护工具

辅助软件维护过程中活动的软件称为软件维护工具,它辅助维护人员对软件代码及其文档进行各种维护活动。软件维护工具主要有:

软件管理和软件支持工具

软件管理和软件支持工具用来辅助管理人员和软件支持人员的管理活动和支持活动,以确保软件高质量地完成。常用的铺助软件管理和软件支持的工具有:

第六章 结构化开发

模块独立

耦合

耦合是模块之间的相对独立性(互相连接的紧密程度)的度量

耦合取决于各个模块之间接口的复杂程度、调用模块的方式以及通过接口的信息类型等。

image

内聚

内聚是对一个模块内部各个元素彼此结合的紧密程度的度量。

image

总结:耦合性和内聚性是模块独立性的两个定性标准,在将软件系统划分模块时,应尽量做到高内聚、低耦合,提高模块的独立性。

系统结构设计原则

  1. 分解-协调原则(考的少)
  2. 自顶向下的原则(考的少)
  3. 信息隐蔽、抽象的原则(考的少)
  4. 一致性原则:统一的规范、统一的标准和统一的文件模式。
  5. 明确性原则:功能明确、接口明确、消除多重功能和无用接口、避免病态连接、降低接口复杂度。
  6. 模块之间的耦合尽可能小,模块的内聚度尽可能高。(高内聚、低耦合)
  7. 模块的扇入系数和扇出系数要合理。(扇入扇出适中)
  8. 模块的规模适当。
  9. 模块的作用范围应该在其控制范围之内。

结构化设计主要包括:

  1. 体系结构设计:定义软件的主要结构元素及其关系。
  2. 数据设计:基于实体联系图确定软件涉及的文件系统的结构及数据库的表结构。
  3. 接口设计:描述用户界面,软件和其他硬件设备、其他软件系统及使用人员的外部接口,以及各种构件之间的内部接口。
  4. 过程设计:确定软件各个组成部分内的算法及内部数据结构,并选定某种过程的表达形式来描述各种算法。

结构图的基本成分包括:模块、调用和数据

黄金准则:用户操纵控制、减轻用户的记忆负担、保持界面一致

软件系统的可维护性评价指标包括:可理解性、可测试性、可修改性、可靠性、可移植性、可使用性和效率。

系统文档

对文档在系统开发人员、项目管理人员、系统维护人员、系统评价人员以及用户之间的多种作用总结如下:

数据流图

数据流图

数据字典

数据字典(DD)是为数据流图中的以下成分做出说明:

数据字典的条目

  1. 数据流条目:对 DFD 中数据流的定义,通常列出该数据流的各组成数据项。
  2. 数据项条目:组成数据流和数据存储的最小元素,是不可再分解的数据单位。
  3. 数据存储条目:对 DFD 中数据存储的定义。
  4. 基本加工条目:用来说明 DFD 中(下层)基本加工的处理逻辑(加工逻辑)。

外部实体不包括在数据字典的条目中

加工逻辑的描述

加工逻辑也称为“小说明”。加工逻辑描述方法有结构化语言、判定表(决策表)和判定树。

  1. 对数据流图的每一个基本加工,必须有一个基本加工逻辑说明
  2. 基本加工逻辑说明必须描述基本加工如何把输入输出数据流变换为输出数据流的加工规则
  3. 加工逻辑说明必须描述加工实现的策略而不是实现加工的细节
  4. 加工逻辑说明中包含的信息是充足的,完备的,有用的,无冗余的。

第七章 面向对象

面向对象基础

注意事项

成员变量 == 数据 == 属性 == 状态

成员函数 == 操作 == 行为 == 方法 == 函数

面向对象的基本概念

面向对象 = 对象(Object)+ 分类(Classification)+ 继承(Inheritance)+通过消息的通信

对象

对象通常可由对象名、属性和方法 3 个部分组成。

方法的重载

  1. 方法名相同 参数个数不同
  2. 方法名相同,参数类型不同
  3. 方法名相同,参数类型的顺序不同

封装

一个对象把属性和行为封装为一个整体。封装是一种信息隐藏的技术

继承

继承是父类和子类之间共享属性和方法的机制。

继承关系中的子类将全部拥有父类的全部属性和方法,但只能用非私有化的属性和方法

多态

同类型的对象,表现出的不同形态。(对象的多种形态)

绑定在编译时进行的,叫做静态绑定,动态绑定是在运行时进行的(动态绑定支持多态)

面向对象设计的原则

面向对象方法中的五大原则:

  1. 单一责任原则:就一个类而言,应该仅有一个引起它变化的原因。
  2. 开放-封闭原则:软件实体应该是可以扩展的,即开发的;但是不可修改的,即封闭的。(扩展开放、修改关闭)
  3. 里氏替换原则: 子类型必须能够替换掉他们的基类型。(基类出现的地方,子类一定可以出现)
  4. 依赖倒置原则:抽象不应该依赖于细节,细节应该依赖于抽象。(依赖于抽象,而不依赖于细节[实现])
  5. 接口分离原则:不应该强迫客户依赖于它们不用的方法。(依赖于抽象,不依赖于具体)

共同封闭原则:包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包产生影响,则将对该包中的所有类产生影响,而对于其他的包不造成任何影响

共同重用原则:一个包中的所有类应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类

1.面向对象分析

面向对象分析是为了获得对应用问题的理解,其主要任务是抽取和整理用户需求并建立问题域精确模型。

  1. 认定对象
  2. 组织对象
  3. 描述对象间的相互作用
  4. 确定对象的操作
  5. 定义对象的内部信息。

2.面向对象设计

面向对象设计是采用协作的对象、对象的属性和方法说明软件解决方案的一种方式,强调的是定义软件对象和这些软件对象如何协作来满足需求,延续了面向对象分析。

  1. 识别类及对象
  2. 定义属性
  3. 定义服务
  4. 识别关系
  5. 识别包

3.面向对象程序设计

面向对象程序设计的实质:选用一种面向对象程序设计语言OOPL):

特定的 OOP 概念一般是通过 OOPL 中特定的语言机制来体现的。

OOP 现在已经扩展到系统分析和软件设计的范畴,出现了面向对象分析和面向对象设计的概念。

4.面向对象测试

面向对象测试是根据规范说明来验证系统设计的正确性。

  1. 算法层:测试类中定义的每个方法,基本上相当于传统软件测试中的单元测试。
  2. 类层:测试封装在同一个类中的所有方法与属性之间的相互作用。在面向对象软件中类是基本模块,因此可以认为这是面向对象测试中所特有的模块测试。
  3. 模板层:测试一组协同工作的类之间的相互作用,大体上相当于传统软件测试中的集成测试,但是也有面向对象软件的特点(例如,对象之间通过发送消息相互作用)。
  4. 系统层:把各个子系统组装成完整的面向对象软件系统,在组装过程中同时进行测试。

事物

UML 中有 4 中事物:

  1. 结构事物:结构事物是 UML 模型中的名词,通常是模型的静态部分,描述概念或物理元素。

    image

  2. 行为事物:行为事物是 UML 模型的动态部分,它们是模型中的动词,描述了跨越时间和空间的行为。

    image

  3. 分组事物:分组事物是 UML 模型的组织部分,是一些由模型分解成“盒子”。

    image

  4. 注释事物:注释事物是 UML 模型的解释部分。这些注释事物用来描述、说明和标注模型的任何元素。

    image

关系

UML 中有 4 种关系:依赖、关联、泛化和实现。

  1. 依赖:依赖是两个事物间的语义关系,其中一个事物(独立事物)发生变化会影响另一个事物(依赖事物)的语义。

    image

  2. 关联:关联是一种结构关系,它描述了一组链,链是对象之间的连接。

image

  1. 泛化:泛化是一种特殊/一般关系,特殊元素(子元素)的对象可替代一般元素(父元素)的对象。子元素共享了父元素的结构和行为。

    image

  2. 实现(了解):实现是类元之间的语义关系,其中一个类元指定了由另一个类元保证执行的契约。

    image

UML

事物

关 系

关 系

类图

类图

类图(Class Diagram)展现了一组对象、接口、协作和它们之间的关系。

符号:

+ : public 公有的

-  : private 私有的

# : protected 受保护的

~ : package 包的

类图用于对系统的静态设计视图建模。通常以下述 3 种方式之一使用类图:

  1. 对系统的词汇建模。
  2. 对简单的协作建模。
  3. 对逻辑数据库模式建模。

image

对象图

对象图展现了某一时刻一组对象以及它们之间的关系,描述了在类图中所建立的事物的实例的静态快照

对象图给出系统的静态设计视图静态进程视图

image

用例图

image

交互图(序列图、通信图)

  1. 序列图(顺序图、时序图) :序列图是场景的图形化表示,描述了对象之间的时间顺序。

    序列图用于展示系统中一个用例和多个对象的行为。

    序列图有两个不同于通信图的特征:

    • 序列图有对象生命线

    • 序列图有控制焦点

      image

  2. 通信图(协作图):通信图强调收发消息的对象的结构组织,在早期的版本中也被称作协作图。

    通信图展现了对象之间的消息流及其顺序。

    通信图有两个不同于序列图的特性:

    • 通信图有路径
    • 通信图有顺序号

image

  1. 交互概览图 (不考)
  2. 计时图 (不考)

状态图

事件,监护条件,动作

image

事件触发转换(迁移)

活动(动作)可以在状态(迁移)内执行,也可以在状态转换时执行。

监护条件是一个布尔表达式。

活动图

构件图(组件图)

image

image

部署图

UML 图汇总

第八章 设计模式

设计模式的要素

设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构

设计模式基本要素:

image

创建型设计模式(5 种)

Simple Factory(简单工厂)

image

/**
 * 简单工厂模式
 */
public class SimpleFactory {
    public static void main(String[] args) {
        Product productA = Factory.createProduct("A");
        productA.info();

        Product productB = Factory.createProduct("B");
        productB.info();

    }
}

class Factory{
    public static Product createProduct(String type){
        Product product =null;

        switch (type){
            case "A":
                product = new ProductA();
                break;
            case "B":
                product = new ProductB();
                break;
            default:
                System.out.println("没有 " + type + " 类型的产品!");
                return null;
        }
        return product;
    }
}

abstract class Product{
    public abstract void info();
}

class ProductA extends Product{

    @Override
    public void info() {
        System.out.println("产品的信息:A");
    }
}

class ProductB extends Product{

    @Override
    public void info() {
        System.out.println("产品的信息:B");
    }
}

1. Factory Method(工厂方法)

1)意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。

2)结构:创建型类模式

image

/**
 * 工厂方法模式
 */
public class FactoryMethod {
    public static void main(String[] args) {

        // 父类 对象名 = new 子类();
        Factory factoryA = new FactoryA();
        Product productA = factoryA.createProduct();
        productA.info();

        Factory factoryB = new FactoryB();
        Product productB = factoryB.createProduct();
        productB.info();

    }
}

interface Factory{
   Product createProduct();
}

class FactoryA implements Factory{

    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

class FactoryB implements Factory{

    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

interface Product{
    void info();
}

class ProductA implements Product{

    @Override
    public void info() {
        System.out.println("产品的信息:A");
    }
}

class ProductB implements Product{

    @Override
    public void info() {
        System.out.println("产品的信息:B");
    }
}

3)适用性:Factory Method 模式适用于

2. Abstract Factory(抽象工厂)

1)意图

提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

2)结构:创建型对象模式

image

/**
 * 抽象工厂模式
 */
public class AbstractFactory {

    public static void main(String[] args) {
        Factory factory1 = new Factory1();
        ProductA productA1 = factory1.createProductA();
        productA1.info();
        ProductB productB1 = factory1.createProductB();
        productB1.info();

        Factory factory2 = new Factory2();
        ProductA productA2 = factory2.createProductA();
        productA2.info();
        ProductB productB2 = factory2.createProductB();
        productB2.info();

    }
}

// 声明一个创建抽象产品对象的操作接口
interface Factory{
   ProductA createProductA();
   ProductB createProductB();
}

// 实现创建具体产品对象的操作
class Factory1 implements Factory{

    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}

class Factory2 implements Factory{

    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}

// 为一类产品对象声明一个接口
interface ProductA{
    void info();
}

interface ProductB{
    void info();
}

// 定义一将被相应的具体工厂创建的产品对象
class ProductA1 implements ProductA{

    @Override
    public void info() {
        System.out.println("产品的信息:A1");
    }
}

class ProductA2 implements ProductA{

    @Override
    public void info() {
        System.out.println("产品的信息:A2");
    }
}

class ProductB1 implements ProductB{

    @Override
    public void info() {
        System.out.println("产品的信息:B1");
    }
}

class ProductB2 implements ProductB{

    @Override
    public void info() {
        System.out.println("产品的信息:B2");
    }
}

3)适用性:Abstract Factory 模式适用于

3. Builder(生成器)

1)意图

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

2)结构:创建型对象模式

image

/**
 * 生成器模式
 */
public class Main {
    public static void main(String[] args) {
        Director director = new Director();

        Builder builder1 = new Builder1();
        director.Construct(builder1);
        Product product1 = builder1.getResult();
        product1.show();

        Builder builder2 = new Builder2();
        director.Construct(builder2);
        Product product2 = builder2.getResult();
        product2.show();
    }
}

class Director{
    public void Construct(Builder builder){
        builder.BuildPart();
    }
}

abstract class Builder{
    public abstract void BuildPart();
    public abstract Product getResult();
}

class Builder1 extends Builder{

    Product product = new Product();

    @Override
    public void BuildPart() {
        product.add("A");
        product.add("B");
        product.add("C");
        product.add("D");
        product.add("E");
        product.add("F");
    }

    @Override
    public Product getResult() {

        return product;
    }
}

class Builder2 extends Builder{

    Product product = new Product();

    @Override
    public void BuildPart() {
        product.add("A");
        product.add("B");
        product.add("C");
    }

    @Override
    public Product getResult() {

        return product;
    }
}

class Product{
    List<String> parts = new ArrayList<String>();

    public void add(String part){
        parts.add(part);
    }

    public void show(){
        System.out.print("产品的组成:");
        for (String part : parts) {
            System.out.print(part + " ");
        }
        System.out.println();
    }
}

3)适用性:Builder 模式适用于

4. Prototype(原型)

1)意图

用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

2)结构:创建型对象模式

image

/**
 * 原型模式
 */
public class Main {

    public static void main(String[] args) {
        Product product1 = new Product(2022,5.28);
        System.out.println(product1.getId()+ " " + product1.getPrice());

        Product product2 = (Product) product1.Chlone();
        System.out.println(product2.getId()+ " " + product2.getPrice());

    }
}

interface Prototype{
    Object Chlone();
}

class Product implements Prototype{

    private int id;
    private double price;

    public Product(){}

    public Product(int id,double price){
        this.id = id;
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public Object Chlone() {
        Product object = new Product();
        object.id = this.id;
        object.price = this.price;

        return object;
    }
}

3)适用性:Prototype 模式适用于

5. Singleton(单例)

1)意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2)结构:创建型对象模式

image

其中:Singleton 指定一个 Instance 操作,允许客户访问它的唯一实例,Instance 是一个类

操作:可能负责创建它自己的唯一实例。

/**
 * 单例模式
 */
public class SingletonPattern {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        Singleton instance3 = Singleton.getInstance();

        System.out.println("instance1: " + instance1);
        System.out.println("instance2: " + instance2);
        System.out.println("instance3: "+ instance3);
    }
}

class Singleton{
     private static Singleton instance = new Singleton();

    private Singleton(){};

    public static Singleton getInstance(){
        return instance;
    }
}

image

3)适用性 Singleton 模式适用于:

结构型设计模式(7 种)

1. Adapter(适配器)

1)意图

将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

2)结构

image

其中:

/**
 * 适配器模式
 */
public class AdapterPattern {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.Request();
    }
}

class Target{
    public void Request(){
        System.out.println("普通请求~");
    }
}

/**
 * 适配器
 */
class Adapter extends Target {
    private Adaptee adaptee = new Adaptee();
    @Override
    public void Request() {
        adaptee.SpecificRequest();
    }
}

class Adaptee{
    public void SpecificRequest(){
        System.out.println("特殊请求~");
    }
}

3)适用性

Adapter 模式适用于:

2. Bridge(桥接)

1)意图

将抽象部分与其实现部分分离,使它们都可以独立地变化。

2)结构

image

/**
 * 桥接模式
 */
public class BridgePattern {
    public static void main(String[] args) {
        Product productA = new ProductA();
        Product productB = new ProductA();

        Color red = new Red();
        productA.setName("产品A");
        productA.setColor(red);
        productA.Operation();

        Blue blue = new Blue();
        productB.setName("产品B");
        productB.setColor(blue);
        productB.Operation();
    }
}

abstract class Product{
    private String name;
    protected Color color;

    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }

    public void setColor(Color color){
        this.color = color;
    }

    public abstract void Operation();
}

interface Color{
    void OperationImpl(String name);
}

class ProductA extends Product{

    @Override
    public void Operation() {
        color.OperationImpl(this.getName());
    }
}

class Red implements Color{

    @Override
    public void OperationImpl(String name) {
        System.out.println(name + ": 红色" );
    }
}

class Blue implements Color{

    @Override
    public void OperationImpl(String name) {
        System.out.println(name + ": 蓝色" );
    }
}

3)适用性(了解)

3. Composite(组合)

1)意图

将对象组合成树型结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。

2)结构

image

其中:

import java.util.*;

/**
 * 组合模式
 */
public class CompositePattern {
    public static void main(String[] args) {
        // 父类名 对象名 = new 子类名();
        AbstractFile root = new Folder("root");

        AbstractFile folderA = new Folder("folderA");
        AbstractFile folderB = new Folder("folderB");

        AbstractFile fileC = new File("fileC");
        AbstractFile fileD = new File("fileD");
        AbstractFile fileE = new File("fileE");

        root.Add(folderA);
        root.Add(folderB);
        root.Add(fileC);

        folderA.Add(fileD);
        folderA.Add(fileE);

        print(root);
    }

    static void print(AbstractFile file){
        file.printName();

        List<AbstractFile> childrenList = file.getChildren();
        if (childrenList == null){
            return;
        }

        for (AbstractFile children : childrenList) {
            print(children);
        }
    }
}

abstract class AbstractFile{
    protected String name;

    public void printName(){
        System.out.println(name);
    }

    public abstract boolean Add(AbstractFile file);
    public abstract boolean Remove(AbstractFile file);
    public abstract List<AbstractFile> getChildren();

}

class Folder extends AbstractFile {

    private List<AbstractFile> childrenList = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    @Override
    public boolean Add(AbstractFile file) {
        return childrenList.add(file);
    }

    @Override
    public boolean Remove(AbstractFile file) {
        return childrenList.remove(file);
    }

    @Override
    public List<AbstractFile> getChildren() {
        return childrenList;
    }
}

class File extends AbstractFile{
    public File(String name) {
        this.name = name;
    }

    @Override
    public boolean Add(AbstractFile filei) {
        return false;
    }

    @Override
    public boolean Remove(AbstractFile file) {
        return false;
    }

    @Override
    public List<AbstractFile> getChildren() {
        return null;
    }
}

3)适用性

Composite 模式下适用于:

4. Decorator(装饰器)

1)意图

动态地给一个对象添加一些额外的职责。就增加功能而言,Decorator 模式比生成子类更加灵活。

2)结构

image

其中:

/**
 * 装饰器模式
 */
public class DecoratorPattern {
    public static void main(String[] args) {
        Person zhangsan = new Student("张三");
        zhangsan = new DecoratorA(zhangsan);
        zhangsan = new DecoratorB(zhangsan);
        zhangsan.Operation();

        System.out.println("==========分割线==============");

        // 对像链
        Person lisi = new DecoratorB(new DecoratorA(new Student("李四")));
        lisi.Operation();

    }
}

abstract class Decorator extends Person{
    protected Person person;
}

class DecoratorA extends Decorator{
    public DecoratorA(Person person){
        this.person = person;
    }

    @Override
    public void Operation() { // 职责
        person.Operation(); // 原本的职责
        System.out.println("写作业~");
    }
}

class DecoratorB extends Decorator{
    public DecoratorB(Person person){
        this.person = person;
    }

    @Override
    public void Operation() { // 职责
        person.Operation(); // 原本的职责
        System.out.println("考试~");
    }
}

abstract class Person{
    protected String name;

    public abstract void Operation(); // 职责

}

class Student extends Person{
    public Student(String name){
        this.name = name;
    }

    @Override
    public void Operation() {
        System.out.println(name + "的职责:学习~");
    }
}

3)适用性

Decorator 模式适用于:

5. Facade(外观)

1)意图

为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

2)结构

image

其中:

import java.util.Scanner;

/**
 */
public class FacadePattern {
    public static void main(String[] args) {
        Facade facade = new Facade();

        facade.methodA();
        facade.methodB();
        facade.methodC();
    }
}

class Facade{
    SubSystemOne subSystemOne;
    SubSystemTwo subSystemTwo;
    SubSystemThree subSystemThree;

    public Facade(){
        subSystemOne = new SubSystemOne();
        subSystemTwo = new SubSystemTwo();
        subSystemThree = new SubSystemThree();
    }

    public void methodA(){
        subSystemOne.methodOne();
    }

    public void methodB(){
        subSystemTwo.methodTwo();
    }

    public void methodC(){
        subSystemThree.methodThree();
    }
}

class SubSystemOne{
    public void methodOne(){
        System.out.println("执行子系统一的功能~");
    }
}

class SubSystemTwo{
    public void methodTwo(){
        System.out.println("执行子系统二的功能~");
    }
}

class SubSystemThree{
    public void methodThree(){
        System.out.println("执行子系统三的功能~");
    }
}

3)适用性

Facade 模式适用于:

6. Flyweight(享元)

1)意图

运用共享技术有效地支持大量细粒度的对象。

2)结构

image

其中:

/**
 * 享元模式 案例1
 */

public class FlyweightPattern {
    public static void main(String[] args) {
        PieceFactory factory = new PieceFactory();

        Piece whitePiece1 = factory.getPiece(0);
        whitePiece1.draw(66,87);
        System.out.println(whitePiece1);

        Piece blackPiece1 = factory.getPiece(1);
        blackPiece1.draw(20,11);
        System.out.println(blackPiece1);

        Piece whitePiece2 = factory.getPiece(0);
        whitePiece1.draw(26, 54);
        System.out.println(whitePiece2);

        Piece blackPiece2 = factory.getPiece(1);
        blackPiece2.draw(12, 34);
        System.out.println(blackPiece2);
    }
}

class PieceFactory{
    private Piece[] pieces = {
      new WhitePiece(),
      new BlackPiece()
    };

    public Piece getPiece(int key){
      if (key == 0) return pieces[0];
      else return pieces[1];
    }
}

abstract class Piece{
    protected String color;

    public abstract void draw(int x,int y);
}

class WhitePiece extends Piece{
    public WhitePiece(){
        this.color = "white";
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("draw a color: "+color + " piece x: " + x + " y: " + y);
    }
}

class BlackPiece extends Piece{
    public BlackPiece(){
        this.color = "black";
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("draw a color: " + color + " piece x: " + x + " y: " + y);
    }
}
/**
 * 享元模式 案例2
 */

public class FlyweightPattern {
    public static void main(String[] args) {
        ShapeFactory factory = new ShapeFactory();

        Random random = new Random();
        String[] colors = {"red","blue","green","whilte","black"};

        for (int i = 1; i <= 10; i++) {
            int x = random.nextInt(colors.length);
            Shape shape = factory.getShape(colors[x]);
            System.out.print("" + i + "个圆:");
            shape.draw(random.nextInt(2022),random.nextInt(528));
        }
    }

}

class ShapeFactory{
    private Map<String,Shape> map = new HashMap<>();

    public Shape getShape(String key){
        if (!map.containsKey(key)) {
            map.put(key, new Circle(key));
            System.out.println("create color: " + key + " circle");
        }
        return map.get(key);
    }
}

abstract class Shape {
    protected String color;

    public abstract void draw(int x, int y);
}

class Circle extends Shape {

    public Circle(String color){
        this.color = color;
    }

    @Override
    public void draw(int x, int y) {
        System.out.println("draw a color: " + color + " circle x:"+ x + " y:" + y);
    }
}

3)适用性

Flyweight 模式适用于:

7. Proxy(代理)

1)意图

为其他对象提供一种代理以控制对这个对象的访问。

2)结构

image

/**
 * 代理模式
 */
public class ProxyPattern {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);

        proxy.buy();
    }
}

interface Subject{
    void buy();
}

class Proxy implements Subject{

    protected RealSubject realSubject;

    public Proxy(RealSubject realSubject){
        this.realSubject = realSubject;
    }

    @Override
    public void buy() {
        System.out.println("办理购买前的手续~");
        realSubject.buy(); // 付钱
        System.out.println("办理购买后的手续~");
    }
}

class RealSubject implements Subject{

    @Override
    public void buy() {
        System.out.println("付钱~");
    }
}

3)适用性 (了解) Poxy 模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候,常见情况有:

行为设计模式(11 种)

1. Chain of Responsibility(责任链)

1)意图

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

2)结构

image

其中:

/**
 * 责任链模式
 */
public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        Handler counsellor = new Counsellor();
        Handler dean = new Dean();
        Handler headmaster= new Headmaster();

        counsellor.setNext(dean);
        dean.setNext(headmaster);

        counsellor.HandRequest(25);
    }

}

abstract class Handler{
    protected Handler next;

    public void setNext(Handler next){
        this.next =next;
    }

    public abstract void HandRequest(int request);
}

class Counsellor extends Handler{

    @Override
    public void HandRequest(int request) {
        if (request <= 7){
            System.out.println("辅导员审批通过~");
        }else {
            if (next != null){
                next.HandRequest(request);
            }else {
                System.out.println("无法审批");
            }
        }
    }
}

class Dean extends Handler{

    @Override
    public void HandRequest(int request) {
        if (request <= 15){
            System.out.println("院长审批通过~");
        }else {
            if (next != null){
                next.HandRequest(request);
            }else {
                System.out.println("无法审批");
            }
        }
    }
}

class Headmaster extends Handler{

    @Override
    public void HandRequest(int request) {
        if (request <= 30){
            System.out.println("校长审批通过~");
        }else {
            if (next != null){
                next.HandRequest(request);
            }else {
                System.out.println("无法审批");
            }
        }
    }
}

3)适用性

Chain of Responsibility 模式适用于以下条件:

2.  Command(命令)

1)意图

将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

2)结构

image

其中:

/**
 * 命令模式
 */
public class CommandPattern {
    public static void main(String[] args) {
        Tv tv = new Tv(); // 接收者 对象 电视机

        Command onCommand = new OnCommand(tv); // 命令对象 开机命令
        Command offCommand = new OnCommand(tv); // 命令对象 关机命令

        Invoker invoker = new Invoker(); //请求者
        invoker.setCommand(onCommand); // 给请求者设置 开机 命令
        invoker.call(); // 请求者去请求命令

        System.out.println("==============分割线===============");

        invoker.setCommand(offCommand); // 给请求者设置 关机命令
        invoker.call(); // 请求者去请求命令

    }
}

class Invoker{ // 请求者
    private Command command; // 命令

    public void setCommand(Command command){ // 设置请求者的命令
        this.command = command;
    }

    public void call(){ // 调用
        command.Execute();
    }
}

interface Command{ // 命令接口
    void Execute(); // 执行命令

}

class OnCommand implements Command{// 开机命令
    private Tv tv;

    public OnCommand(Tv tv){
        this.tv = tv;
    }

    @Override
    public void Execute() {
        tv.OnAction();
    }
}

class OffCommand implements Command{ // 关机命令
    private Tv tv;

    public OffCommand(Tv tv){
        this.tv = tv;
    }

    @Override
    public void Execute() {
        tv.OffAction();
    }
}

class Tv{
    public void OnAction(){ // 开机行为
        System.out.println("电视机开机了...");
    }

    public void OffAction(){ // 关机行为
        System.out.println("电视机关机了...");
    }
}

3)适用性

Command 模式适用于:

3. Interpreter(解释器)

1)意图

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

2)结构

image

/**
 * 解释器模式
 */
public class InterpreterPattern {

    public static void main(String[] args) {

        Context context = new Context();

        context.check("A区的开发人员");
        context.check("B区的调试人员");
        context.check("C区的测试人员");

        System.out.println("========分割线=============");

        context.check("D区的程序员");
        context.check("D区的测试员");
        context.check("C区的程序员");

    }
}

class Context{
    private String[] regions = {"A区","B区","C区"};
    private String[] persions = {"开发人员","测试人员","调试人员"};
    private NonterminalExpression nonterminal;

    public Context(){
        TerminalExpression region = new TerminalExpression(regions);
        TerminalExpression person = new TerminalExpression(persions);
        nonterminal = new NonterminalExpression(region,person);
    }

    public void check(String info){
        boolean result = nonterminal.Interpret(info);
        if (result){
            System.out.println("识别成功~");
        }else {
            System.out.println("识别失败~");
        }
    }

}

interface Expression{
    boolean Interpret(String info);
}

class NonterminalExpression implements Expression{

    private TerminalExpression region;
    private TerminalExpression person;

    public NonterminalExpression(TerminalExpression region,TerminalExpression person){
        this.region =region;
        this.person = person;
    }

    @Override
    public boolean Interpret(String info) {
        String[] str = info.split("");
        // B区鹅调试人员 --> str = {"B区","调试人员"};
        return region.Interpret(str[0]) && person.Interpret(str[1]);
    }
}

class TerminalExpression implements Expression{

    private Set<String> set = new HashSet<>();

    public TerminalExpression(String[] data){
        for (String str : data) {
            set.add(str);
        }
    }

    @Override
    public boolean Interpret(String info) {
        return set.contains(info);
    }
}

3)适用性

Interpreter 模式适用于当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,以下情况效果最好:

4. Iterator(迭代器)

1)意图

提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。

2)结构

image

其中:

/**
 * 迭代器模式
 */
public class IteratorPattern {

    public static void main(String[] args) {
        BookAggregate bookAggregate = new BookAggregate();

        String[] books = {"数据结构","操作系统","计算机网络","计算机组成原理"};
        double[] prices = {10.24,20.48,40.96,81.92};

        for (int i = 0; i < 4; i++) {
            bookAggregate.Add(new Book(books[i],prices[i]));
        }

        Iterator iterator = bookAggregate.CreateIterator();
        while (iterator.hasNext()) {
            Book book = (Book) iterator.next();
            System.out.println("书名:" + book.getName() + " 价格:" + book.getPrice());
        }

    }

}

interface Iterator{
    boolean hasNext();
    Object next();
}

class BookIterator implements Iterator{
    private int index;
    private BookAggregate bookAggregate;

    public BookIterator(BookAggregate bookAggregate){
        this.index = 0;
        this.bookAggregate = bookAggregate;
    }

    @Override
    public boolean hasNext() {
        if (index < bookAggregate.getSize()){
            return true;
        }
        return false;
    }

    @Override
    public Object next() {
        Object obj = bookAggregate.get(index);
        index ++ ;
        return obj;
    }
}

class BookAggregate implements Aggregate{

    private List<Book> list = new ArrayList<>();

    public void Add(Book book){
        list.add(book);
    }

    public Book get(int index){
        return list.get(index);
    }

    public int getSize(){
        return list.size();
    }

    @Override
    public Iterator CreateIterator() {
        return new BookIterator(this);
    }
}

interface Aggregate{
    Iterator CreateIterator();
}

class Book{
    private String name;
    private double price;

    public Book(String name,double price){
        this.name = name;
        this.price = price;
    }

    public String getName(){
        return name;
    }

    public double getPrice(){
        return price;
    }
}

3)适用性

Iterator 模式适用于:

5. Mediator(中介者)

1)意图

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

2)结构

image

其中:

/**
 * 中介者模式
 */
public class MediatorPattern {
    public static void main(String[] args) {
        ConcreteMediator mediator = new ConcreteMediator();

        Colleague1 colleague1 =new Colleague1(mediator);
        Colleague2 colleague2 = new Colleague2(mediator);

        mediator.setColleague1(colleague1);
        mediator.setColleague2(colleague2);

        colleague1.sendMessage("软考加油~");
        colleague2.sendMessage("祝你上岸~");

    }
}

abstract class Colleague{
    protected Mediator mediator;
}

class Colleague1 extends Colleague{
    public Colleague1(Mediator mediator){
        this.mediator = mediator;
    }

    public void sendMessage(String message){
        mediator.sendMessage(message,this);
    }

    public void Notify(String message){
        System.out.println("同事1收到消息:" + message);
    }
}

class Colleague2 extends Colleague{
    public Colleague2(Mediator mediator){
        this.mediator = mediator;
    }

    public void sendMessage(String message){
        mediator.sendMessage(message,this);
    }

    public void Notify(String message){
        System.out.println("同事2收到消息:" + message);
    }
}

abstract class Mediator{
    public abstract void sendMessage(String message,Colleague colleague);
}

class ConcreteMediator extends Mediator{
    private Colleague1 colleague1;
    private Colleague2 colleague2;

    public void setColleague1(Colleague1 colleague1){
        this.colleague1 = colleague1;
    }

    public void setColleague2(Colleague2 colleague2){
        this.colleague2 = colleague2;
    }

    @Override
    public void sendMessage(String message, Colleague colleague) {
        if (colleague == colleague1){
            // 让同事2收到消息
            colleague2.Notify(message);
        }else {
            // 让同事1收到消息
            colleague1.Notify(message);
        }
    }
}

3)适用性

Mediator 模式适用于:

6. Memento(备忘录)

1)意图

在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

2)结构

image

/**
 * 备忘录模式
 */
public class MementoPattern {
    public static void main(String[] args) {
        Caretaker caretaker = new Caretaker();
        Originator originator = new Originator();

        originator.setState("1024");
        Memento backup1 = originator.createMemento();
        caretaker.addMemento(backup1);

        originator.setState("2048");
        Memento backup2 = originator.createMemento();
        caretaker.addMemento(backup2);

        originator.setState("4096");
        Memento backup3 = originator.createMemento();
        caretaker.addMemento(backup3);

        System.out.println(originator.getState());
        caretaker.showMemento();

        Memento memento1 = caretaker.getMemento(2);
        originator.setState(memento1.getState());

        System.out.println("根据第2次备份还原之后的状态为:" + originator.getState());
    }
}

class Originator{ // 原发器
    private String state;

    public void setState(String state){
        this.state = state;
    }

    public String getState(){
        return state;
    }

    public Memento createMemento(){
        return new Memento(state);
    }

    public void setMemento(Memento memento){
        state = memento.getState();
    }
}

class Memento{ // 备忘录
    private String state;

    public String getState(){
        return state;
    }

    public Memento(String state){
        this.state = state;
    }
}

class Caretaker{ // 管理者
    private List<Memento> mementoList = new ArrayList<>();

    public void addMemento(Memento memento){
        mementoList.add(memento);
    }

    public Memento getMemento(int index){
        // 判断参数是否合法
        if (index >=1 && index <= mementoList.size()) {
            return mementoList.get(index - 1);
        }
        return null;
    }

    public void showMemento(){
        int cnt = 1;
        for (Memento memento : mementoList) {
            System.out.println("" + cnt + "次备份,状态为:" + memento.getState());
            cnt ++;
        }
    }
}

3)适用性

Mement 模式适用于:

7. Observer(观察者)

1)意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

2)结构

image

其中:

/**
 * 观察者模式
 */
public class ObserverPattern {
    public static void main(String[] args) {
        Subject subjectA = new ConcreteSubject("目标A");

        Observer observerB = new ConcreteObserver("张三",subjectA);
        Observer observerC = new ConcreteObserver("李四",subjectA);
        Observer observerD = new ConcreteObserver("王五",subjectA);

        subjectA.setState("更新了");
    }
}

interface Subject { // 目标接口
    void Attach(Observer observer); // 添加观察者

    void Detach(Observer observer); // 删除观察者

    void Notify(); // 状态改变后,通知所有观察者

    void setState(String state); // 设置状态(改变状态)
    String getState(); // 获取状态
}

class ConcreteSubject implements Subject {
    private String name;
    private String state;

    private List<Observer> observerList;

    public ConcreteSubject(String name) {
        state = "未更新";
        this.name = name;
        observerList = new ArrayList<>();
    }

    @Override
    public void Attach(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void Detach(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void Notify() {
        for (Observer observer : observerList) {
            observer.update();
        }
    }

    @Override
    public void setState(String state) {
        this.state = state;

        System.out.println(name + "的状态发生变化,变化后的状态为:" + state);
        Notify();
    }

    @Override
    public String getState() {
        return state;
    }
}

interface Observer { // 观察者接口
    void update();  // 收到通知,更新观察者的状态
}

class ConcreteObserver implements Observer {

    private String name;
    private String state;

    private Subject subject;

    public ConcreteObserver(String name, Subject subject) {
        this.name = name;
        this.subject = subject;
        subject.Attach(this);
        state = subject.getState();
    }

    @Override
    public void update() {
        System.out.println(name + " 收到通知");
        state = subject.getState(); //  让当前观察者的状态 和 目标改变后的状态保持一致
        System.out.println(name + " 改变后的状态为:"+state);
    }
}

3)适用性

Observer 模式适用于:

8. State(状态)

1)意图

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

2)结构

image

/**
 * 状态模式
 */

public class StatePattern {
    public static void main(String[] args) {
        Context context = new Context(); // count = 3

        System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());

        context.Request(); // 购买一个饮料 count = 2
        context.Request(); // 购买一个饮料 count = 1
        context.Request(); // 购买一个饮料 count = 0

        System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());

        context.Request(); // 无货,等待补货

        System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());

        context.Request(); // 购买一个饮料 count = 4
        System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());

    }
}

class Context{ // 贩卖机
    private int count;

    private State state;

    public Context(){
        count = 3;
        state = new StateA();
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void Request(){  // 购买饮料
        state.Handle(this);
    }
}

interface State{
    void Handle(Context context);
}

class StateA implements State{

    @Override
    public void Handle(Context context) {
        int count = context.getCount();

        if (count >= 1){
            System.out.println("购买成功~");
            context.setCount(count - 1);

            if (context.getCount() == 0){
                context.setState(new StateB()); // 设置为无货状态
            }
        }else {
            System.out.println("购买失败~");
        }
    }
}

class StateB implements State{

    @Override
    public void Handle(Context context) {
        int count = context.getCount();

        if (count == 0){
            System.out.println("购买失败!等待补货~");

            context.setCount(5);
            System.out.println("补货成功,请重新购买~");

            context.setState(new StateA());
        }
    }
}

3)适用性

State 模式适用于:

9. Strategy(策略)

1)意图

定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。

2)结构

image

/**
 * 策略模式
 */
public class StrategyPattern {
    public static void main(String[] args) {

        OperationContext context = new OperationContext(new Addstrategy());
        context.Operation(20,17);

        context = new OperationContext(new Substrategy());
        context.Operation(20,17);

        context = new OperationContext(new Multstrategy());
        context.Operation(20,17);
    }
}

class OperationContext{
    private Strategy strategy;

    public OperationContext(Strategy strategy){
        this.strategy =strategy;
    }

    public void Operation(int a, int b){
        strategy.TwoNumberOperation(a,b);
    }
}


interface Strategy{
    void TwoNumberOperation(int a,int b);
}

class Addstrategy implements Strategy{

    @Override
    public void TwoNumberOperation(int a, int b) {
        System.out.println(a + b);
    }
}

class Substrategy implements Strategy{

    @Override
    public void TwoNumberOperation(int a, int b) {
        System.out.println(a - b);
    }
}

class Multstrategy implements Strategy{

    @Override
    public void TwoNumberOperation(int a, int b) {
        System.out.println(a * b);
    }
}

3)适用性

Strategy 模式适用于:

10. Template Method(模板方法)

1)意图

定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

2)结构

image

其中:

/**
 * 模板方法模式
 */
public class TemplateMethodPattern {
    public static void main(String[] args) {
        // 父类名 对象名 = new 子类名();

        Person student = new Student();
        Person teacher = new Teacher();

        student.TemplateMethod();

        System.out.println("=========分割线=============");

        teacher.TemplateMethod();
    }
}

abstract class Person{
    public void TemplateMethod(){
        System.out.println("上课 去教室");
        PrimitiveOperation1();
        System.out.println("下课 离开教室");
        PrimitiveOperation2();
    }

    public abstract void PrimitiveOperation1(); // 原语操作 1:上课过程 学生 听课... 老师 讲课
    public abstract void PrimitiveOperation2(); // 原语操作 2:作业  学生 写作业 提交作业... 老师批改作业 打分数
}

class Student extends Person{

    @Override
    public void PrimitiveOperation1() {
        System.out.println("学生:听课 学习 做笔记 提出问题");
    }

    @Override
    public void PrimitiveOperation2() {
        System.out.println("学生:写作业 提交作业");
    }
}

class Teacher extends Person{

    @Override
    public void PrimitiveOperation1() {
        System.out.println("老师:上课 讲课 解答问题 布置作业");
    }

    @Override
    public void PrimitiveOperation2() {
        System.out.println("老师:批改作业 打分数");
    }
}

3)适用性

Template Method 模式适用于:

11. Visitor(访问者)

1)意图

表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。

2)结构

image

其中:

/**
 * 访问者模式
 */
public class VisitorPattern {
    public static void main(String[] args) {
        PersonStructure structure = new PersonStructure();

        Visitor1 visitor1 = new Visitor1();
        System.out.println("访问者1的访问记录:");
        structure.Accept(visitor1);
        System.out.println("学生年龄的总和:" + visitor1.getStudentAgeSum() +" 老师年龄的总和:" + visitor1.getTeacherAgeSUm());

        System.out.println("=========分割线==============");

        Visitor2 visitor2 = new Visitor2();
        System.out.println("访问者2的访问记录:");
        structure.Accept(visitor2);
        System.out.println("学生的最高成绩:" + visitor2.getMaxScore() + " 老师的最高工龄:" + visitor2.getMaxWorkYear());

    }
}

interface Visitor{
    void VistStudent(Student student); // 访问
    void vistTeacher(Teacher teacher); // 访问老师
}

class Visitor1 implements Visitor{ // 访问者1 分别统计学生和老师的年龄总和
    private int studentAgeSum = 0;
    private int teacherAgeSUm =0;

    public int getStudentAgeSum() {
        return studentAgeSum;
    }

    public int getTeacherAgeSUm() {
        return teacherAgeSUm;
    }

    @Override
    public void VistStudent(Student student) {
        System.out.println("访问者1访问学生:" + student.getName() + " 年龄:" + student.getAge());
        studentAgeSum += student.getAge();
    }

    @Override
    public void vistTeacher(Teacher teacher) {
        System.out.println("访问者1访问老师:" + teacher.getName() + " 年龄:" + teacher.getAge());
        teacherAgeSUm += teacher.getAge();
    }
}

class Visitor2 implements Visitor{ // 访问者2 分别求出 学生的最高成绩 以及 老师的最高工龄
    private int maxScore = -1;
    private int maxWorkYear = -1;

    public int getMaxScore() {
        return maxScore;
    }

    public int getMaxWorkYear() {
        return maxWorkYear;
    }

    @Override
    public void VistStudent(Student student) {
        System.out.println("访问者2访问学生:" + student.getName() + " 成绩:" + student.getScore());
        maxScore = Math.max(maxScore,student.getScore());
    }

    @Override
    public void vistTeacher(Teacher teacher) {
        System.out.println("访问者2访问老师:" + teacher.getName() + " 工龄:" + teacher.getWorkYear());
        maxWorkYear = Math.max(maxWorkYear,teacher.getWorkYear());
    }
}

class PersonStructure{
    private List<Person> personList = new ArrayList<>();

    public PersonStructure(){
        personList.add(new Student("张三",20,70));
        personList.add(new Student("李四",21,80));
        personList.add(new Student("王五",22,90));

        personList.add(new Teacher("李老师",26,3));
        personList.add(new Teacher("陈老师",27,4));
        personList.add(new Teacher("刘老师",28,5));
    }

    public void Accept(Visitor visitor){
        for (Person person : personList) {
            person.Accept(visitor);
        }
    }
}

abstract class Person{
    private String name;
    private int age;


    public Person(String  name,int age){
        this.name = name;
        this.age = age;
    }

    public String getName(){
        return name;
    }

    public int getAge() {
        return age;
    }

    public abstract void Accept(Visitor visitor);
}

class Student extends Person{

    private int score;
    public Student(String name,int age,int score){
        super(name,age);
        this.score = score;
    }

    public int getScore(){
        return score;
    }

    @Override
    public void Accept(Visitor visitor) {
        visitor.VistStudent(this);
    }
}

class Teacher extends Person{
    private int workYear;
    public Teacher(String name,int age,int workYear){
        super(name,age);
        this.workYear = workYear;
    }

    public int getWorkYear(){
        return workYear;
    }

    @Override
    public void Accept(Visitor visitor) {
        visitor.vistTeacher(this);
    }
}

3)适用性

Visitor 模式适用于:

第九章 算法设计与分析

时间复杂度

算法时间复杂度以算法中基本操作重复执行的次数(简称为频度)作为算法的时间度量。一般不必要精确计算出算法的时间复杂度,只要大致计算出相应的数量级即可,如 O(1)、O(㏒₂n)、O(n)或 O(n²)等。


image

递归式时间复杂度:递归的次数 x 每次递归的时间复杂度

主方法。主方法也称为主定理,给出了求解以下形式的递归式的快速方法。

image

空间复杂度

非递归:O(1) O(n) O(n²)

回溯法

n 皇后问题

image

#include<stdio.h>
#include"stdlib.h"

int Place(int *Column,int index){
    int i;
    for(i=1;i<index;i++){
        int Column_differ = abs(Column[index] - Column[i]);
        int Row_differ = abs(index - i);
        if(Column[i] == Column[index] || Column_differ == Row_differ)
            return 0;
    }
    return 1;
}

void N_Queue(int n){
    int Column_Num[n+1];
    int index = 1;
    int i;

    int answer_num = 0;
    for(i=1;i<=n;i++)
        Column_Num[i] = 0;
    while(index>0){
        Column_Num[index]++;
        while(Column_Num[index] <= n && !Place(Column_Num,index))
            Column_Num[index]++;
        if(Column_Num[index] <=n){
            if (index == n) {
                answer_num++;

                printf("方案%d",answer_num);

                for(i=1;i<= n;i++){
                    printf("%d ",Column_Num[i]);
                }
                printf("\n");
            }else {
                index++;
                Column_Num[index]=0;
            }
        }else {
            index--;
        }
    }
}

int main(){
    N_Queue(6);
    return 0;
}

分治法

递归有两个基本要素:

分支算法在每一层递归上都有 3 个步骤:

  1. 分解。将原问题分解成一系列子问题。
  2. 求解。递归地求解各子问题。若子问题足够小,则直接求解。
  3. 合并。将子问题的解合并成原问题的解。
归并排序算法
#include<stdio.h>

#define INT_MAX 2147483647
/**
 * 归并排序
**/
void Merge(int A[],int p,int q,int r){
    int n1 = q - p + 1,n2 = r -q,i,j,k;
    int L[50],R[50];
    for(i=0;i<n1;i++)
        L[i] = A[p+i];
    for(j=0;j<n2;j++)
        R[j] = A[q+j+1];
    L[n1] = INT_MAX;
    R[n2] = INT_MAX;
    i=0;
    j=0;
    for(k=p;k<r+1;k++){
        if(L[i] < R[j]){
            A[k] = L[i];
            i++;
        }else{
            A[k]=R[j];
            j++;
        }
    }
}

void MergeSort(int A[],int p,int r){
    int q;
    if(p < r){
        q = (p+r) / 2;
        MergeSort(A, p, q);
        MergeSort(A, q+1, r);
        Merge(A, p, q,r);
    }
}

int main(){
    int A[] = {4,1,3,6,7,5,2,9};
    MergeSort(A, 0, 7);

    int i;
    for (i = 0; i<8; i++) {
        printf("%d ",A[i]);
    }
    printf("\n");
    return 0;
}

image

最大字段和问题

image

#include<stdio.h>
#include<stdlib.h>

int MaxSubSum(int * Array,int left,int right){
    int sum = 0;
    int i;
    if(left == right){ /*分解到单个整数,不可继续分解*/
        if(Array[left] > 0)
            sum = Array[left];
        else
            sum = 0;
    }else{
        /*从 left 和 right 的中间分解数组*/
        int center = (left + right)/2; /*划分的位置*/
        int leftsum = MaxSubSum(Array, left, center);
        int rightsum = MaxSubSum(Array, center+1, right);
        /*计算包括 center 的最大值,判断是情形1、情形2还是情形3*/
        int s1 = 0;
        int lefts = 0;
        for(i = center;i >= left;i--){
            lefts = lefts + Array[i];
            if(lefts > s1)
                s1 = lefts;
        }
        int s2 = 0;
        int rights = 0;
        for(i = center + 1;i<= right;i++){
            rights = rights + Array[i];
            if(rights > s2)
                s2 = rights;
        }
        sum = s1 + s2;

        /*情形1*/
        if (sum < leftsum) {
            sum = leftsum;
        }
        /*情形2*/
        if(sum < rightsum){
            sum = rightsum;
        }
    }
         return sum;
}

int main(){
    int *Array = (int *)malloc(6*sizeof(int));
    Array[0] = -2;
    Array[1] = 11;
    Array[2] = -4;
    Array[3] = 13;
    Array[4] = -5;
    Array[5] = -2;

    int result = MaxSubSum(Array, 0, 5);
    printf("%d\n",result);

    return 0;
}

image

动态规划法

0-1 背包问题
#include<stdio.h>

#define N 4 // 物品数量
#define W 5 // 背包容量

int max(int a,int b){
    return a > b ? a : b;
}

int main(){
    int v[] = {0,2,4,5,6}; // 物品价值数组
    int w[] = {0,1,2,3,4}; // 物品重量数组

    int f[N + 1][W + 1] = {}; // 子问题解数组

    int i,j;
    for(i=1;i<=N;i++){
        for(j=1;j<=W;j++){
            if(j >= w[i]){ // 选第 i 个物品的前提条件
                // 等于不选第 i 个物品 和 选第 i 个物品 两者的较大值
                f[i][j] = max(f[i-1][j],f[i-1][j-w[i]] + v[i]);
            }else{ // 不选第 i 个物品
                f[i][j] = f[i - 1][j]; // 等于从前 i-1 个物品中选,背包容量为 j 时的最大价值
            }
        }
    }

    printf("%d\n",f[N][W]);

    return 0;
}

时间复杂度:O(N*W) N:物品数量 W:背包容量

矩阵连乘问题

贪心法

部分背包问题
#include<stdio.h>

#define N 5     // 物品数量
#define W 100   // 背包容量

// 显示物品价值、重量、单位重量价值数组
void show(int v[],int w[],double vw[]){
    int i;

    printf("物品价值数组:");
    for(i = 1;i<=N;i++) printf("%d ",v[i]);
    printf("\n");

    printf("物品重量数组:");
    for(i = 1;i<=N;i++) printf("%d ",w[i]);
    printf("\n");

    printf("物品单位重量价值数组:");
    for(i = 1;i<=N;i++) printf("%0.1lf ",vw[i]);
    printf("\n");



}

double Max_Value(int v[],int w[],double vw[]){
    double result = 0.0;

    int i;
    int w_temp = W;
    for(i=1;i<=N;i++){
        if(w_temp >= w[i]){
            result = result + v[i];

            w_temp = w_temp - w[i];
        }else{
            break;
        }
    }

    if(w_temp > 0 && i<=N){
        result = result + w_temp * vw[i];
    }
    return result;
}

int main(){

    int v[] = {0,65,20,30,60,40};   // 物品价值数组
    int w[] = {0,30,10,20,50,40};   // 物品重量数组

    double vw[N + 1]; // 物品单位重量价值数组

    int i;
    // 初始化 物品单位重量价值数组
    for(i = 1;i<=N;i++) vw[i] = (double) v[i] / w[i];

    show(v, w, vw);

    double result =Max_Value(v, w, vw);
    printf("\nreslut %.1lf\n",result);

    return 0;
}

第十章 数据库

概念数据模型(E-R 图)

三级模式结构

两级映像

数据库系统在三级模式之间提供了两级映像:模式/内模式映像、外模式/模式映像。保证了数据库中的数据具有较高的逻辑独立性和物理独立性。

  1. 模式/内模式映像:实现了概念模式和内模式之间的相互转换。
  2. 外模式/模式映像:实现了外模式和概念模式之间的相互转换。
  3. 数据的物理独立性:需要修改概念模式和内模式之间的映像。
  4. 数据的逻辑独立性:需要修改外模式和概念模式之间的映像。

关系型模式的基本术语

完整性约束

完整性规则保证用户对数据库做修改时不会破坏数据的一致性。

关系代数运算符

image

SQL 语言

SQL 语言的分类

SQL 控制语句

关系模式的范式

候选码中包含的属性称为主属性、不包含在候选码中的属性称为非主属性。若候选码多于一个,可以选定其中的一个为主码。

范式之间的关系

image

1NF(第一范式)

定义:若关系模式 R 每一个分量是不可再分的数据项,则关系模式 R 属于第一范式。

1NF 可能存在的问题:

问题的原因是 1NF 中可能存在部分函数依赖。

2NF(第二范式)

定义:若关系模式 R∈1NF,且每一个非主属性完全依赖于码,则关系模式 R∈2NF。

当 1NF 消除了非主属性对码的部分函数依赖,则称为 2NF。

可能存在数据冗余和更新异常等问题。

3NF(第三范式)

2NF 消除了非主属性对码的传递函数依赖,则称为 3NF。

属于 3NF 的关系模式 R 可能存在主属性对候选码的部分依赖和传递依赖。

BC 范式(BCNF)

定义:R 是一个关系模式,F 是它的依赖集,R 属于 BCNF,当且仅当其 F 中的每个依赖的决定因素必定包含 R 的某个候选码。

BC 范式已经消除了插入和删除异常

规范化步骤

NF 到 4NF 之间的转换关系:

范式转换关系
1NF每一个分量是不可再分的数据项
2NF1NF 消除了部分函数依赖后满足 2NF
3NF2NF 消除了非主属性对候选码的传递函数依赖后满足 3NF
BCNF3NF 消除了主属性对候选码的部分和传递函数依赖后满足 BCNF
4NFBCNF 消除非平凡且非函数依赖的多值依赖后满足 4NF

image

数据库设计

新奥尔良法是目前公认的数据库设计方法,它将数据库设计分为以下几个阶段:

  1. 用户需求分析:收集用户需求,确定系统边界
  2. 概念结构设计:E—R 图
  3. 逻辑结构设计:E—R 图转换成关系模式、规范化
  4. 物理结构设计

需求分析

概念结构设计

对需求分析阶段所得到的数据进行分类、聚集和概括,确定实体、属性和联系。

E-R 图之间的冲突

  1. 属性冲突。同一属性可能会存在于不同的分 E-R 图。
  2. 命名冲突。异名同义、同名异议
  3. 结构冲突。同一实体在不同的分 E—R 图中有不同的属性,同一对象在某一个 E—R 图中被抽象为实体,而在另一个 E—R 图中被抽象为属性,需要统一。

逻辑结构设计

逻辑结构设计阶段的主要工作步骤包括:

事物管理

事务是一个操作序列,这些操作“要么都做,要么都不做”。

事务和程序是两个不同的概念,一般一个程序可包含多个事务。

事务的 ACID 性质:

分布式数据库

第十一章 计算机网络

网络的设备

广播域冲突域
物理层(集线器)××
数据链路层(交换机)×
网络层(路由器)

协议簇

image

image

TCP 和 UDP

补充:

  1. TCP 和 UDP 都是应用于传输层的网络协议。
  2. TCP 有助于提供可靠性,UDP 有助于提高传输的高速率性。

电子邮件协议 SMTP 和 POP3

ARP 和 RARP

DHCP(动态主机配置协议)

URL

协议名://主机名.域名.域名后缀.域名分类/目录/网页文件

组织模式含义地理模式含义
com商业机构cn中国
edu教育机构hk中国香港
gov政府机构mo中国澳门
mil军事部门tw中国台湾
net主要网络支持中心us美国
org上述以外组织uk英国
int国际组织jp日本

IPv6 128 位地址空间、IPv4 32 位地址空间。

浏览器

internet 地址

Internet 地址格式主要有两种书写形式:

IP 地址

IP 地址:Internet 中的主机地址实际上是用 IP 地址来唯一标识的。

IP 地址有两种:

通常 IP 地址是指 IPv4。

IPv4

每个 IPv4 地址都由 4 个小于 256 的数字组成(每个数字 8 位,共 32 位),数字之间用.分开,可分为 5 类:

image

补充:

子网掩码

网络软件和路由器使用子网掩码来识别报文是仅存放在网络内部还是被路由转发到其他地方。

子网掩码是用来指明特定的 IP 地址中的网络号和主机号部分。子网掩码的格式与 IP 地址相同:

image

IPv6

IPv6 具有长达 128 位的地址空间,可以彻底解决 IPv4 地址不足的问题。

IPv6 理论上能表示的地址个数:2^128^=3.4×10^38^

在想象得到的将来,IPv6 的地址空间是不可能用完的。

无线通信技术

流行的无线通信技术有 WiFi、蓝牙等。其中,蓝牙覆盖范围最小、通信距离最短。

ipconfig 命令

ipconfig 命令的用法如下:

参数说明示例
无参数显示所有网络适配器的 IP 地址、子网掩码和缺省网关值ipconfig
/all显示所有网络适配器的完整 TCP/IP 配置信息,包括 DHCP 服务是否已启动ipconfig /all
/displaydns显示本地 DNS 内容ipconfig /displaydns
/flushdns清除本地 DNS 缓存内容ipconfig /flushdns
/registerdnsDNS 客户端手工向服务器进行注册ipconfig /registerdns
/releaseDHCP 客户端手工释放 IP 地址/释放所有连接ipconfig /release
/renewDHCP 客户端手工向服务器刷新请求(重新申请 IP 地址)/更新所有适配器ipconfig /renew

信息安全

防火墙技术

防火墙是建立在内外网络边界上的过滤封锁机制

补充内容

  1. 包过滤防火墙

    • 过滤型的防火墙通常是直接转发报文,它对用户完全透明,速度较快。对网络层的数据报文进行检查。处在网络层(TCP)和数据链路层(IP)
    • 优点:防火墙对每条传出网络的包实行低水平控制。每个 IP 字段都被检查,如:源地址、目标地址、协议和端口号
    • 缺点:不能防范黑客攻击、不支持应用层协议、不能处理新的安全威胁。
  2. 应用代理网关防火墙

    • 内网用户对外网的访问变成防火墙对外网的访问,然后再由防火墙转发给内网用户。处在应用层、传输层和网络层。
    • 优点:检查应用层、传输层和网络层的协议特征对数据包的检测能力比较强
    • 缺点:难以配置、处理速度非常慢(网络整体性能低)
  3. 状态检测技术防火墙

    • 状态检测技术防火墙结合了代理防火墙的安全性和包过滤防火墙的高速度等优点。在不损失安全性的基础上,提高了代理防火墙的性能

病毒

计算机病毒可以分为:

计算机病毒的特征包括:传播性、破坏性、隐蔽性、感染性、潜伏性、触发性等。

worm 表示蠕虫病毒、Trojan 表示特洛伊木马(秘密潜伏且能够通过远程网络进行控制的恶意程序)、Backdoor 表示后门病毒、Macro 表示宏病毒

补充病毒与木马的区别

【病毒】:

【木马】:

网络攻击

  1. 主动攻击:拒绝服务攻击(Dos)、分布式拒绝服务(DDos)、认证处理、信息篡改、资源使用、欺骗、伪装、重放等
  2. 被动攻击:嗅探、信息收集等

网络安全

安全需求

第十二章 知识产权

著作权(也称为版权):是指作者对其创作的作品享有的人身权和财产权。

人身权包括:

财产权(受时间限制)包括:

职务作品开发人员(软件设计师)只享有**署名权(不能被继承)**

应用技术

试题一

题目形式:文字说明 + 两张数据流图 + 问题


数据流图(DFD)

数据流图的基本图形元素包括数据流、加工、数据存储和外部实体。

image

问题一(易)

找实体名称

写法: E1 :病人 E2:护理人员 E3:医生

问题二(易)

找数据存储名称

写法:D1:XX 表 XX 文件

D1:销售订单表 D2:库存表 D3:生产计划表 D 4:配方表 D5:采购订单表

问题三(15~20 分钟)

题型:

三个解题方法

  1. 父图子图平衡
  2. 加工既有输入数据流也有输出数据流
  3. 数据守恒

注意事项:数据流的起点和终点必须有一个是加工

答题格式:

image

试题二

数据库设计:

实体

实体用矩形表示,通常矩形框内写明实体名。

例如职工与家属的联系,家属总是属于某职工的(在关系模式中需要依赖职工而存在),所以家属是弱实体。

image

联系

联系用菱形表示,通常菱形框内写明联系名。 1:1:

image

image

1:*:

*:*:只能转化成一个独立的关系模式,关系的码是多方实体的码构成的属性组

属性

椭圆形表示,并用无向边将其与相应的实体连接起来

  1. 简单属性和复合属性。简单属性是原子的、不可再分的复合属性可以细分为更小的部分(即划分为别的属性)。
  2. 单值属性和多值属性。单独的一个值。
  3. 派生属性。派生属性可以从其他属性得来。

试题三

UML 的关系

UML 的关系

image

UML 的图

UML 的图

  1. UML 类图

    • 依赖、泛化、关联关系、实现(少见)
    • 接口(不考)
    • 协作(不考)
  2. UML 用例图

    • 用例。
    • 参与者。
    • 用例之间的扩展关系(<<extend>>)和包含关系(<<include>>),参与者和用例之间的关联关系,用例与用例以及参与者与参与者之间的泛化关系。
      • image

试题四

N 皇后问题

  1. 按行来摆放皇后
  2. 判断同一列 Qi列 = Qj列
  3. 判断同一条斜线:|Qi行 - Qj行| = |Qi列 - Qj列|

试题六

模式总结

简单工厂模式

简单工厂模式

工厂方法模式

工厂方法模式

抽象工厂模式

抽象工厂模式

生成器模式

生成器模式

原型模式

原型模式

适配器模式

适配器模式

桥接模式

桥接模式

组合模式

组合模式

装饰器模式

装饰器模式

享元模式

享元模式

命令模式

命令模式

观察者模式

观察者模式

状态模式

状态模式

策略模式

策略模式

访问者模式

访问者模式

中介者模式

中介者模式



上一篇
记录一次项目组 AI 项目的技术选型
下一篇
使用 PicGo + Github + jsdelivr 搭建图床