计算器的基本硬件系统由运算器、控制器、存储器、输入设备、输出设备的5大部件组成。
中央处理单元(CPU)是计算机系统的核心部件,它负责获取程序指令、对指令进行译码并加以执行。
CPU主要由运算器、控制器、寄存器组和内部总线等部件组成。
运算器:运算器只能完成运算。
控制器:控制器用于控制整个 CPU 的工作,它决定了计算机运行过程的自动化。它不仅要保证程序的正确执行,而且要能够处理异常事件。
补充:指令 == 操作码 + 地址码
位(比特) 最小数据单位 | bit、b | 8b=1B |
---|---|---|
字节 最小存储单位 | byte、B | 1B = 8b |
千字节 | KB | 1KB = 1024B |
兆字节 | MB | 1MB = 1024KB |
吉字节 | GB | 1GB = 1024MB |
太字节 | TB | 1TB = 1024GB |
进制 | 英文简写 |
---|---|
二进制 | B |
八进制 | O |
十进制 | D |
十六进制 | H |
按权展开求和:n进制 ————> 十进制 每一位八进制数与三位二进制数对应
除n取余法:十进制 ————> n进制 每一位十六进制数与四位二进制数对应
进制加减法:加法:逢n进制进一 减法:借一当n
原码:总共有n位。最高位是符号位,0表示正号,1表示负号。其余n - 1为位表示数值的绝对值。
反码:正数的反码与原码相同,负数的反码则是其绝对值按位求反。
补码:正数的补码与其原码和反码相同,负数的补码则是等于其反码的末位加1。补码可以简化计算机运算部件的设计
移码:在补码的基础上取反符号位。
补充
浮点数使用两个定点数来分别表示实数的尾数(F)和阶码(E)。其一般形式为:N = 2^E * F
[0.5,1]
2^*k* − 1≥ *n*+k
RISC精简指令集计算机 | CISC复杂指令集计算机 | |
---|---|---|
指令种类 | 少、精简 | 多、丰富 |
指令复杂度 | 低(简单) | 高(复杂) |
指令长度 | 固定 | 变化 |
寻址方式 | 少 | 复杂多样 |
实现(译码)方式 | 硬布线控制逻辑(组合逻辑控制器) | 微程序控制技术 |
通用寄存器数量 | 多、大量 | 一般 |
流水线技术 | 支持 | 不支持 |
计算机中的流水线技术是把一个重复的过程分解为若干个子过程,每个子过程与其他子过程并行进行。
若要执行n条指令:
(*n*−1)
Cache存储器部分用来存放主存的部分拷贝(副本)信息。控制部分的功能是判断CPU要访问的信息是否在Cache存储器中,若在即为命中,若不在则没有命中。命中时直接对Cache存储器寻址;未命中时,要按照替换原则决定主存的一块信息放到Cache存储器的哪一块里。
计算机在执行程序过程中,当遇到急需处理的事件时,暂停当前正在运行的程序,转去执行有关服务程序,处理完后自动返回源程序,这个过程称为中断。
总线是连接计算机有关部件的一组信号线,是计算机中用来传送信息代码的公共通道。
采用总线结构主要有以下优点:
在计算机系统中采用总线结构,便于实现系统的积木化构造,同时可以减少信息传输线的数量。
微机中的总线分为:
常见总线:
对称密钥(私钥、私有密钥加密)算法(共享密钥加密算法) | 非对称密钥(公钥、公开密钥加密)算法 |
---|---|
DES | RSA |
3DES | ECC |
RC-5 | DSA |
IDEA | |
AES | |
RC4 |
Hash函数
MD5 摘要算法(128位散列值)
SHA-1 安全散列算法
认证是处理主动攻击
R = R₁R₂···Rn
R = 1 - (1-R₁)(1-R₂)···(1-Rn)
X | Y | 逻辑与 | 逻辑或 | 逻辑异或 | 逻辑同或 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 | 0 |
1 | 1 | 1 | 1 | 0 | 1 |
函数的定义包括两部分:函数首部和函数体。函数的定义描述了函数做什么和怎么做。
函数定义的一般形式为:
返回值的类型 函数名(形式参数表) //函数首部 函数名(实参表);
{
函数体;
}
(1)值调用。若实现函数调用时将实参的值传递给相应的形参, 则称为是传值调用。在这种方式下形参不能向实参传递信息。
(2)引用调用。引用是 C++ 中引入的概念,当形式参数为引用类型时,形参名实际上是实参的别名,函数中对形参的访问和修改实际上就是针对相应实参所做的访问和改变。
符号表:不断收集、记录和使用源程序中一些相关符号的类型和特征等信息,并将其存入符号表中。记录源程序中各个字符的必要信息,以辅助语义的正确性检查和代码生成。
1)词法分析
输入:源程序
输出:记号流
词法分析阶段的主要作用是:分析构成程序的字符及由字符按照构造规则构成的符号,是否符合程序语言的规定。
2)语法分析
输入:记号流
输出:语法树(分析树)
语法分析阶段的主要作用是:对各条语句的结构进行合法性分析,分析程序中的句子结构是否正确。
3)语义分析
输入:语法树(分析树)
语义分析阶段的主要作用是进行类型分析和检查
语义分析阶段可以发现程序中所有的语法错误
语义分析阶段不能发现程序中所有的语义错误
语义分析阶段可以发现静态语义错误,不能发现动态语义错误,动态语义错误运行时才能发现(eg:除数为0时只能在运行阶段检查出来)
4)中间代码生成
常见的中间代码有:后缀式、三地址码、三元式、四元式和树(图)等形式。
中间代码与具体的机器无关(不依赖具体的机器),可以将不同的高级程序语言翻译成同一种中间代码。
中间代码可以跨平台。
因为与具体的机器无关,使用中间代码有利于进行与机器无关的优化处理和提高编译程序的可移植性。
6)目标代码生成
目标代码生成阶段的工作与具体的机器密切相关
寄存器的分配工作处于目标代码生成阶段
程序设计语言的绝大多数语法规则可以采用上下文无关文法进行描述。
上下文无关文法属于乔姆斯基定义的2型文法。
中缀式:a ? b ===> 后缀式:ab? 后缀式转中缀式可以用:栈
+-*/
的优先级和数学一致,优先级相同,从右向左
中间代码有多种形式,其中树与后缀表示形式适用于解释器,而编译器多采用与机器指令格式较接近的四元式形式。
根据生成的语法树,按照不同的方式遍历即可生成形式不同的表达式:
1-2*(3+4)/5
转为后缀表达式 --> 1234+5/*-
逆波兰式其实就是后缀式。
这章我没怎么看,大家自己补充一下
计算机系统由两部分组成:
通常把未配置软件的计算机称为裸机。
操作系统目的是:为了填补人与机器之间的鸿沟,即建立用户与计算机之间的接口,而为裸机配置的一种系统软件。
操作系统也包括了系统软件。
操作系统在计算机系统中的地位:
操作系统是用户与计算机之间的接口,它在计算机系统中占据重要而特殊的地位,所有其他软件,如编辑程序、汇编程序、编译程序、数据库管理系统等系统软件,以及大量的应用软件都是建立在操作系统基础上的,并得到它的支持和取得它的服务。
程序顺序执行时的主要特征包括:顺序性、封闭性和可再现性。
程序并发执行时的主要特征包括:失去了程序的封闭性、程序和机器的执行程序的活动不再一一对应、并发程序之间的相互制约性。
在多道程序系统中,进程在处理器上交替运行,状态也不断地发生变化,因此进程一般有3种基本状态:运行、就绪和阻塞。
进程 | CPU | 资源 |
---|---|---|
运行 | √ | √ |
就绪 | × | √ |
阻塞 | × | × |
在多道程序环境的系统中存在多个可以并发执行的进程,故进程间必然存在资源共享和相互合作的问题。进程通信是指各个进程交换信息的过程。
同步:合作进程间的直接制约问题。
进程间的同步:是指在系统中一些需要相互合作,协同工作的进程,这样的相互联系称为进程的同步。
例如,进程A向缓冲区送数据,进程B从缓冲区取数据加工,当进程B要取数据加工时,必须是进程A完成了向缓冲区送数据的操作,否则进程B必须停下来等待进程A的操作结束。
互斥:申请临界资源进程间的间接制约问题。
进程间的互斥:是指系统中多个进程因争用临界资源而互斥执行。
临界资源:在多道程序系统环境中,那些一次只能供一个进程使用的资源。如打印机、共享变量和表格等。
临界区管理的原则:
临界区:是进程中对临界资源实施操作的那段程序。
对互斥临界区管理的4条原则如下:
信号量机制是一种有效的进程同步与互斥工具。
信号量机制主要有:
整型信号量:
信号量是一个整型变量,根据控制对象的不同被赋予不同的值。信号量分为如下两类:
1
或资源的数目。0
或某个正整数。信号量 S 的物理意义:
PV操作:实现进程同步与互斥的常用方法。
P操作和V操作是低级通信原语,在执行期间不可分割。其中:
P操作(减):表示申请一个资源;
定义:S := S−1(S表示信号量)
V操作(加):表示释放一个资源。
定义:S := S+1
P减V加,P进V出。
利用PV操作实现进程的互斥:
mutex
的初始值为1;利用PV操作实现进程的同步:
实现进程的同步可用一个信号量与消息联系起来。
信号量的值:
0
:表示希望的消息未产生;0
:表示希望的消息已经存在。假定信号量S表示某条消息,进程可以:
当有 n 个进程,m个资源,且每个进程所需要的资源数为k,并且系统采用的分配策略是轮流地为每个进程分配资源时,判断是否发生死锁的公式如下:
m >= n * (k-1)+1
死锁的处理策略主要有4种:鸵鸟策略(即不理睬策略)、预防策略、避免策略和检测与解除死锁。
做题方法:先分配,再申请
传统进程有两个基本属性:
- 可拥有资源的独立单位;
- 可独立调度和分配的基本单位。
引入线程的原因是,进程的系统必须付出较大的时空开销。引入线程后,将传统进程的两个基本属性分开:
线程是进程中的一个实体,是被系统独立分配和调度的基本单位。
线程的特点:
线程因其具有许多传统进程所具有的特性,故称为"轻型进程";而传统进程称为"重型进程"。
线程分为:
某些系统同时实现了两种类型的线程。
与线程不同的是,不论是系统进程还是用户进程,在进行切换时,都要依赖于内核中的进程调度。因此,不论是什么进程都是与内核有关的,是在内核支持下进行切换的。
程序在执行时将呈现出局部性规律,即在一段时间内,程序的执行仅局限于某个部分。相应地,它所访问的存储空间也局限于某个区域内。
程序的局限性表现在以下两个方面:
时间局限性:
空间局限性:指一旦程序访问了某个存储单元,则在不久的将来,其附近的存储单元也最有可能被访问。
分页原理:
在为进程分配主存时,将进程中若干页分别装入多个不相邻接的块中。
地址结构:
其中,页内地址是同一页(页号)中的偏移量。
分页的过程是由操作系统完成的,对用户是透明的,所以用户不必关心分页的过程,其优点是能有效地提高主存利用率,其缺点是不易实现共享。
结合分页和分段存储管理方式,形成一种新的存储管理方式,即段页式存储管理。段页式系统有两种系统的优点。
段页式系统的基本原理是:
段页式地址空间的结构:
缓冲技术可提高外设利用率,尽可能使外设处于忙状态。缓冲技术可以采用两种方式:
单缓冲工作过程图:
当第1块数据送入用户工作区后(进行数据处理),缓冲区是空闲的,可以传送第2块数据(输入)。即第1块数据的处理C1与第2块数据的输入T2是可以并行的,以此类推:
(前提是c要小于T)计算公式为:
(T + M)* n + c
先来先服务(FCFS):根据进程请求访问磁盘的先后次序进行调度。
最短寻道时间优先(SSTF,最短移臂算法):该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,使得每次的寻道时间最短。
扫描算法(SCAN,电梯调度算法):总是从磁头当前位置开始,沿磁头的移动方向去选择离当前磁头最近的那个柱面的请求。如果沿磁头的方向无请求访问时,就改变磁头的移动方向。
在这种调度方法下磁头的移动类似于电梯的调度,所以它也称为电梯调度算法。
单向扫描算法(CSCAN,循环扫描算法):为了减少上述SCAN缺点中存在的这种延迟,算法规定磁头只做单向移动。
例如,只是自里向外移动,从当前位置开始沿磁头的移动方向去选择离当前磁头最近的那个柱面访问,如果沿磁头的方向无请求访问时,磁头立即返回到最里面的欲访问的柱面,再亦即将最小柱面号紧接着最大柱面号构成循环,进行循环扫描。
总结:
双缓冲进一步加快I/O的速度,提高了设备的利用率。其工作基本过程是在设备输入时,先将数据输入到缓冲区1,装满后便转向缓冲2。
双缓冲工作过程图:
双缓冲的工作特点是,可以实现对缓冲中数据的输入T和提取M,与CPU的计算C,三者并行工作:
(前提是M +c <T)计算公式为:
T * n + M + c
文件控制块(FCB):用于文件的描述和控制的数据结构,实现了文件的“按名存取”。
文件控制块至少要包括文件名和存放文件的物理地址。
文件控制块也称为文件的说明或文件目录项(简称目录项)。
文件目录:文件控制块的有序集合。
即文件目录是由文件控制块组成的,专门用于文件的检索。
文件控制块中包含以下信息:
基本信息类:例如文件名、文件的物理地址、文件长度和文件块数等。
存取控制信息类:文件的存取权限。
UNIX中,用户分成三类:
以上三类用户对文件的权限为:
使用信息类:文件建立日期、最后一次修改日期、最后一次访问的日期、当前使用的 信息(如打开文件的进程数、在文件上的等待队列)等。
组织好文件的目录是设计文件系统的重要环节,文件目录结构的组织方式直接影响到文件的存取速度,关系到文件的共享性和安全性。
常见的目录结构有:
一级目录结构:一级目录的整个目录组织是一个线性结构,在整个系统中只需建立一张目录表,系统为每个文件分配一个目录项。
优点:结构简单;
缺点:查找速度慢,不允许重名和不便于实现文件共享等。
主要用在单用户环境中。
二级目录结构:为了克服一级目录结构存在的缺点引入了二级目录结构。
二级目录结构的组成为:
优点:提高了检索目录的速度,较好地解决了重名问题。
缺点:该结构虽然能有效地将多个用户隔离开(这种隔离在各个用户之间完全无关时是一个优点),但当多个用户之间要相互合作去共同完成一个大任务,且一个用户又需要去访问其他用户的文件时,这种隔离便成为一个缺点,因为这种隔离使诸用户之间不便于共享文件。
多级目录结构:在多道程序设计系统中常采用多级目录结构。
多级目录结构是树型目录结构。从根结点向下,每一个结点是一个目录,叶结点是文件。
在采用多级目录结构的文件系统中,用户要访问一个文件,必须指出文件所在的路径名:
路径名:从某个目录开始到该文件的通路上所有各级目录名拼起来得到的。
在各目录名之间、目录名与文件名之间需要用分隔符隔开。
绝对路径名:指从根目录开始的完整路径。
全文件名:指绝对路径名加上该文件的文件名。
相对路径名:从当前所在目录开始到其他目录或文件的路径。
位示图是一种空闲空间管理方法。通过在外存上建立一张位示图,记录文件存储器的使用情况。
位示图用二进制的一位来表示一个物理块的使用情况:
0
:表示空闲;1
:表示占用。例如:
位示图的大小由磁盘空间的大小(物理块总数)决定。
位示图的描述能力强,适合各种物理结构。
做题技巧:
(n-1)*32 ~~~ n*32-1
n*32 ~~~(n+1)*32-1
CMM 将软件过程改进分为以下5个成熟度级别:
1)初始级(最低成熟度)
软件过程的特点是杂乱无章,有时甚至很混乱,几乎没有明确定义的步骤,项目的成功完全依赖个人的努力和英雄式核心人物的作用。
2)可重复级
建立了基本的项目管理过程和实践来跟踪项目费用、进度和功能特性,有必要的过程准则来重复以前在同类项目中的成功。
3)已定义级
管理和工程两方面的软件过程已经文档化、标准化,并综合成整个软件开发组织的标准软件过程。
4)已管理级
制定了软件过程和产品质量的详细度量标准。软件过程的产品质量都被开发组织的成员所理解和控制。
5)优化级(最高成熟度)
加强了定量分析,通过来自过程质量反馈和来自新观念、新技术的反馈使过程能不断持续地改进。
CMMI 提供了两种表示方法:
1)阶段式模型
阶段式模型的结构类似于 CMM,它关注组织的成熟度。
有五个成熟度等级:
2)连续式模型
连续式模型关注每个过程域的能力,一个组织对不同的过程域可以达到不同的过程域能力。
CMMI 中包括6个过程域能力等级:
软件开发过程模型是指为了有效地开发、维护和更新软件系统,提出的一系列步骤、阶段和方法的系统框架,以实现提高软件质量、加快开发速度和降低开发成本的目的。
常见的软件开发过程模型包括瀑布模型、增量模型、演化模型(原型模型、螺旋模型)和喷泉模型。
瀑布模型是一种线性的软件开发过程模型,开发流程严格按照顺序依次进行,每个阶段都必须完成后才能进入下一个阶段。瀑布模型包括需求分析、设计、编码、测试和维护五个阶段。
瀑布模型:
优点:
缺点:
瀑布模式适合用于:
增量模型采用了逐步完善的思路,将软件的开发过程划分为一个个的增量,每个增量都能够独立实现某一或多项功能或特性。在逐步实现的过程中,可以不断根据需求变化来进行迭代,从而保证最终的软件达到客户需求和期望。
增量模型作为瀑布模型的一个变体,具有瀑布模型的所有优点。此外,它还有以下优点:
缺点:
量模型适合用于:
演化模型是迭代的过程模型,使得软件开发人员能够逐步开发出更完整的软件版本。演化模型特别适用于对软件需求缺乏准确认识的情况。典型的演化模型有原型模型和螺旋模型等。
并非所有的需求都能够预先定义。大量的实践表明,在开发初期很难得到一个完整的、准确的需求规格说明。原因有:
原型模型:
原型的目的是能快速、低成本地构建原型系统。
能够采用原型方法是因为开发工具的快速发展,使得能够迅速地开发出一个让用户看得见、摸得着的系统框架。这样,对于计算机不是很熟悉的用户就可以根据这个框架提出自己的需求。
开发原型系统首先确定用户需求,开发初始原型,然后征求用户对初始原型的改进意见,并根据意见修改原型:
根据使用原型的目的不同,原型可以分为:
对于复杂的大型软件,开发一个原型往往达不到要求。
螺旋模型将瀑布模型和演化模型结合起来,加入了两种模型均忽略的风险分析(以风险为驱动),弥补了这两种模型的不足。
螺旋模型将开发过程分为几个螺旋周期,每个螺旋周期大致和瀑布模型相符合:
螺旋模型属于面向对象开发模型。
螺旋模型适用于:
优点:
缺点:
喷泉模型:喷泉模型克服了瀑布模型不支持软件重用和多项开发活动集成的局限性
泉模型使开发过程具有以下性质或特点:
迭代性:意味着模型中的开发活动常常需要重复多次,在迭代过程中不断地完善软件系统。
无间隙性:指在开发活动(如分析、设计、编码)之间不存在明显的边界。
喷泉不像瀑布模型那样,在需求分析活动结束后才开始设计活动,在设计活动结束后才开始编码活动,而是允许各开发活动交叉、迭代地进行。
喷泉模型的各个阶段没有明显的界线,开发人员可以同步进行。
支持软件重用。
优点:可以提高软件项目的开发效率,节省开发时间。
缺点:
阶段 | 里程碑 | 关注 | 产生 |
---|---|---|---|
初始阶段 | 生命周期目标 | 项目的初创活动 | 构想文档、业务用例、项目计划、风险评估 |
精化阶段 | 生命周期架构 | 需求分析和架构演进 | 补充需求分析、软件架构描述、架构原型制品 |
构建阶段 | 初始运作功能 | 系统的构建 | 具有最初运作能力的软件产品 |
移交阶段 | 产品发布 | 软件提交方面的工作 | 产品发布版本 |
敏捷方法是一种反应灵活、拥有高度互动性和以人为本的软件开发方法。它的核心是通过不断地交付成果和及时反馈,来满足客户需求和不断变化的业务环境。以下是敏捷方法中的一些常见实践:
极限编程是为了降低需求变更所带来的成本,旨在提高软件质量和对客户需求变化的适应性,期望能够让软件开发达到低成本、低缺陷、高产出、高回报(最小投入得到最大结果)的效果。
极限编程(XP)软件开发方式有以下性质:
XP由价值观、原则、实践和行为4个部分组成,他们之间彼此相互依赖、关联,并通过行为贯穿于整个生存周期:
使用迭代的方法。
有6个基本原则:
敏捷统一过程采用以下原理来构建软件系统:
采用经典的UP阶段性活动(初始、精化、构建和转换),提供了一系列活动,能够使团队为软件项目构想出一个全面的过程流。
在每个活动里,一个团队迭代使用敏捷,并将有意义的软件增量尽可能快地交付给最终用户。每个AUP迭代执行以下活动:
软件需求是指用户对目标软件系统在功能、行为、性能、设计约束等方面的期望。通常,这些需求包括:
功能需求:考虑系统要做什么,在何时做,在何时以及如何修改或升级。
性能需求:考虑软件开发的技术性指标。
用户或人的因素:考虑用户的类型。
环境需求:考虑未来软件应用的环境,包括硬件和软件。
界面需求:
文档需求:考虑需要哪些文档,文档针对哪些读者。
数据需求:
资源使用需求:
安全保密要求:
可靠性要求:
软件成本消耗与开发进度需求:
其他非功能性要求:
如采用某种开发模式,需要确定:
软件需求的出处:
设计软件系统总体结构
数据结构及数据库设计
编写概要设计文档
评审
根据详细设计进行代码的编写,得到可以运行的软件,并进行单元测试。
意义:系统测试是为了发现错误而执行程序的过程,成功的测试是发现了至今尚未发现的错误的测试。 目的:测试的目的就是希望能以最少的人力和时间发现潜在的各种错误和缺陷。
单元测试的测试内容
单元测试过程
集成测试是进行一些旨在发现与接口相关的错误的测试,其目标是利用已通过单元测试的构件建立设计中描述的程序结构。
自顶向下集成测试是一种构造软件体系结构的增量方法。
自顶向下集成不需要驱动模块,需要桩模块。
自底向上集成测试就是从原子模块(程序结构的最底层构件)开始进行构造和测试。
自底向上集成需要驱动模块,不需要桩模块。
测试方法分为:
静态测试:指被测试程序不在机器上运行,而是采用以下手段对程序进行检测
动态测试:指通过运行程序发现错误。在对软件产品进行动态测试时可以采用以下两种测试方法:
测试用例由以下组成:
在设计测试用例时,应当包括:
黑盒测试在完全不考虑软件的内部结构和特性的情况下,测试软件的外部特性
白盒测试根据程序的内部结构和逻辑来设计测试用例,对程序的路径和过程进行测试,检查是否满足设计的需要。
逻辑覆盖:考察用测试数据运行被测程序时,对程序逻辑的覆盖程度。主要的逻辑覆盖标准有6种,它们的覆盖程度从低到高为:
语句覆盖:指选择足够的测试数据,使被测试程序中的每条语句至少执行一次。语句覆盖对程序执行逻辑的覆盖很低,因此一般认为它是很弱的逻辑覆盖。
判定覆盖(分支覆盖):指设计足够的测试用例,使得被测程序中的每个判定表达式至少获得一次“真”/“假”值。判定覆盖的判定表达式是指判定表达式整体。判定覆盖要比语句覆盖更强一些。
条件覆盖:指构造一组测试用例,使得每一判定语句中每个逻辑条件的各种可能的值至少满足一次。
条件覆盖的判定语句是指判定表达式下的判定语句(如果有),即用AND
、OR
等逻辑运算符连接起来的语句(不包含逻辑运算符的语句)。
判定/条件覆盖:指设计足够的测试用例,使得判定中每个条件的所有可能取值(真/假)至少出现一次,并使每个判定本身的判定结果(真/假)也至少出现一次。结果取判定覆盖和条件覆盖的并集。
判定/条件覆盖同时满足:
条件组合覆盖:指设计足够的测试用例,使得每个判定中条件的各种可能值的组合都至少出现一次。
满足条件组合覆盖的测试用例一定满足:
路径覆盖:指覆盖被测试程序中所有可能的路径。
循环覆盖
基本路径测试
白盒测试逻辑覆盖技术总结(覆盖程度从低到高):
逻辑覆盖 | 说明 |
---|---|
语句覆盖 | 每条语句执行一次 |
分支(判定)覆盖 | 每个分支获得一次True/False |
条件覆盖 | 每个分支中的每个逻辑条件的所有可能取值满足一次 |
判定/条件覆盖 | 分支覆盖 + 条件覆盖 |
条件组合覆盖 | 每个判定中条件的各种可能值的组合都出现一次 |
路径覆盖 | 覆盖被测试程序中所有可能的路径 |
系统是否能被很好地维护,可以用系统的可维护性这一指标来衡量。
系统可维护性的评价指标
软件文档与软件维护:
软件文档是软件可维护性的决定因素。文档是软件产品的一部分,并且编写高质量的文档可以提高软件开发的质量。
软件系统的文档分为:
可维护性是所有软件都应具有的基本特点,必须在开发阶段保证软件具有可维护的特点。在软件工程的每一个阶段都应考虑并提高软件的可维护性,在每个阶段结束前的技术审查和管理复查中应该着重对可维护性进行复审(如将来要改进的部分和可能会修改的部分)。
做题技巧:
软件维护:
沟通图是指项目中人员或部门之间的沟通用一条无向边连接起来,所构成图即为沟通图。沟通图中的路径称为沟通路径。
软件项目中沟通路径m的计算公式(人数n):
m= (n−1)n÷2
m = n -1
COCOMO模型是一种精确的、易于使用的成本估算模型。COCOMO模型按其详细程度分为:
和其前身COCOMO一样,COCOMOII也是一种层次结构的估算模型,被分为3个阶段性模型,分别对应三种不同的规模估算选择:
应用组装模型:在软件工程的前期阶段使用,这时用户界面的原型开发、对软件和系统交互的考虑、性能的评估以及技术成熟度的评价是最重要的。
规模估算选择:对象点。
早期设计阶段模型:在需求己经稳定并且基本的软件体系结构己经建立时使用。
规模估算选择:功能点。功能点可转换为代码行。
体系结构阶段模型:在软件的构造过程中使用。
规模估算选择:代码行。
PERT图是一个有向图:
PERT图的优点:
PERT图不能清晰地描述任务之间的并行情况。
项目活动图是一种有向图(与PERT图十分类似):
弧:表示活动。弧的权值表示活动的持续时间。
顶点:表示项目里程碑。
特殊的里程碑:
项目活动图的关键路径:按照PERT图的方法求出松弛时间为0的、从开始里程碑到结束里程碑的路径。
关键路径的长度:为结束里程碑的最早时刻(或最晚时刻)。它可以用来表示项目完成的最少时间。
软件配置管理的主要目标包括:
主要内容有两种版本:
配置数据库分为以下三类:
一般认为软件风险包含两个特性:
项目风险威胁到项目计划。项目风险是指以下各方面的潜在问题以及它们对软件项目的影响:
以下方面的不确定性也属于项目风险因素:
技术风险威胁到要开发软件的质量及交付时间。技术风险是指以下方面的潜在问题:
设计
实现
接口
验证
维护
规格说明的歧义性
技术的不确定性
技术陈旧
“前沿”技术
商业风险威肋到要开发软件的生存能力,且常常会危害到项目或产品。5个主要的商业风险如下:
风险识别试图系统化地指出对项目计划(估算、进度、资源分配等)的威胁。识别出已知风险和可预测风险后,项目管理者首先要做的是:
识别风险的一种方法是建立风险条目检查表(未考察),主要用来识别下列几种类型中的一些已知风险和可预测风险:
与上述每个主题相关的问题可以针对每一个软件项目来回答。根据这些问题的答案,项目管理者就可以估计风险产生的影响。另一种风险条目检查表格式:仅仅列出与每一种类型有关的特性,最终给出一组风险因素和驱动因子以及它们发生的概率。
风险因素(未考察)包括:
风险预测又称风险估计,它试图从两个方面评估一个风险:
通常,项日计划人员与管理人员、技术人员一起进行以下4步风险预测活动:
一种简单的风险预测技术是建立风险表:
第1列:列出所有的风险(由风险识别活动得到);
第2~4列:列出每个风险的:
风险所产生的影响可用一个数字来表示:
评估风险影响:发生风险时,有3个因素可能会影响风险所产生的后果:
风险的本质:指当风险发生时可能带来的问题。
风险的范围:
风险的时间:
整体的风险暴露度(RE):
RE = P * C
P是风险发生的概率,C是风险发生时带来的项目成本
一种对风险评估很有用的技术就是定义风险参照水准。对于大多数软件项目来说,有3种典型的风险参照水准
风险控制的目的是辅助项目组建立处理风险的策略。一个有效的策略必须考虑以下3个问题:
风险避免:
应对风险的最好办法是主动地避免风险,即在风险发生前分析引起风险的原因,然后采取措施,以避免风险的发生。
风险监控:
项目管理者应监控某些因素,这些因素可以提供风险是否正在变高或变低的指示。
RMMM计划:
风险管理策略可以包含在软件项目计划中,或者风险管理步骤也可以组织成一个独立的风险缓解、监控和管理计划(RMMM计划)。RMMM计划将所有风险分析工作文档化,并由项目管理者作为整个项目计划中的一部分来使用。建立了RMMM计划,而且项目己经启动之后,风险缓解及监测步骤也就开始了:
风险缓解:一种问题规避活动。
风险监测:一种项目跟踪活动。
这种监测活动有3个主要目的:
风险监测的另一个任务就是试图找到“起源”(在整个项目中是哪些风险引起了哪些问题)。
讨论软件质量首先要了解软件的质量特性,目前己经有多种软件质量模型来描述软件质量特性,如:
ISO/IEC 9126软件质量模型由3个层次组成:
质量子特性的含义:
简单记忆:
功能性 | 可靠性 | 易用性 | 效率 | 可维护性 | 可移植性 |
---|---|---|---|---|---|
适合、安全、准、互、依 | 成、容、恢 | 理、学、操 | 时、资 | 分、改、稳、测 | 适应、安装、一、替 |
Mc Call也给出了一个三层模型框架:
通常,把“质量”理解为“用户满意程度”。为了使得用户满意,有以下两个必要条件:
设计质量:设计的规格说明书符合用户的要求。
设计质量的评审对象:
程序质量:程序按照设计规格说明所规定的情况正确执行。程序质量的评审通常是从开发者的角度进行,与开发技术直接相关。
程序质量的评审对象:
软件的规格说明分为:
提高软件质量和可靠性的技术大致可分为两类:
实现容错的主要手段是冗余。冗余是指对于实现系统规定功能是多余的那部分资源,包括:
由于加入了这些资源,有可能使系统的可靠性得到较大的提高。通常,冗余技术分为4类:
结构冗余:结构冗余是通常采用的冗余技术,按其工作方法可以分为:
静态冗余:静态冗余通过表决和比较来屏蔽系统中出现的错误。
动态冗余:动态冗余的主要方式是多重模块待机储备。当系统测试到某工作模块出现错误时,就用一个备用模块来顶替它并重新运行。这里包括以下过程:
动态冗余有以下两种方式:
热备份系统:每当一个出错模块被其他备用模块顶替后,冗余系统相当于进行了一次重构。
在热备份系统中,备用模块在待机过程中的失效率为0。
冷备份系统:各备用模块在其待机时可与主模块一同工作,也可不工作。
混合冗余:兼有静态元余和动态冗余的长处。
信息冗余:指为检测或纠正信息在运算或传输中的错误需外附加的一部分信息。
时间冗余:指以重复执行指令或程序来消除瞬时错误带来的影响。
冗余附加技术:指为实现上述冗余技术所需的资源和技术,包括:程序、指令、数据、存放和调动它们的空间和通道等。在屏蔽硬件错误的容错技术中,冗余附加技术包括:
在屏蔽软件错误的容错系统中,冗余附加技术的构成包括:
对应于软件开发过程的各种活动,软件开发工具通常有:
辅助软件维护过程中活动的软件称为软件维护工具,它辅助维护人员对软件代码及其文档进行各种维护活动。软件维护工具主要有:
软件管理和软件支持工具用来辅助管理人员和软件支持人员的管理活动和支持活动,以确保软件高质量地完成。常用的铺助软件管理和软件支持的工具有:
耦合是模块之间的相对独立性(互相连接的紧密程度)的度量。
耦合取决于各个模块之间接口的复杂程度、调用模块的方式以及通过接口的信息类型等。
内聚是对一个模块内部各个元素彼此结合的紧密程度的度量。
总结:耦合性和内聚性是模块独立性的两个定性标准,在将软件系统划分模块时,应尽量做到高内聚、低耦合,提高模块的独立性。
结构化设计主要包括:
结构图的基本成分包括:模块、调用和数据
黄金准则:用户操纵控制、减轻用户的记忆负担、保持界面一致
软件系统的可维护性评价指标包括:可理解性、可测试性、可修改性、可靠性、可移植性、可使用性和效率。
构造分层DFD时需要注意:
适当命名
画数据流而不是控制流
避免一个加工有过多的数据流
分解尽量均匀
先考虑确定状态,忽略琐碎的细节
随时准备重画
软件维护的内容包括:
对文档在系统开发人员、项目管理人员、系统维护人员、系统评价人员以及用户之间的多种作用总结如下:
用户与系统分析人员在系统规划和系统分析阶段通过文档进行沟通。这里的文档主要包括:
系统开发人员与项目管理人员通过文档在项目期内进行沟通。这里的文档是指项目管理文件,主要有:
有了这些文档可以:
系统测试人员与系统开发人员通过文档进行沟通。
系统方案说明书
系统开发合同
系统设计说明书
测试计划
系统测试人员再将评估结果撰写成系统测试报告。
系统开发人员与用户在系统运行期间进行沟通。
系统开发人员与系统维护人员通过文档进行沟通。
系统开发总结报告
系统设计说明书
用户与维修人员在运行维护期间进行沟通。
用户在使用信息系统的过程中,将运行过程中的问题进行记载,形成:
系统维护人员根据以下文档对系统进行维护和升级:
数据字典(DD)是为数据流图中的以下成分做出说明:
外部实体不包括在数据字典的条目中
加工逻辑也称为“小说明”。加工逻辑描述方法有结构化语言、判定表(决策表)和判定树。
注意事项:
成员变量 == 数据 == 属性 == 状态
成员函数 == 操作 == 行为 == 方法 == 函数
面向对象 = 对象(Object)+ 分类(Classification)+ 继承(Inheritance)+通过消息的通信
对象通常可由对象名、属性和方法 3 个部分组成。
一个对象把属性和行为封装为一个整体。封装是一种信息隐藏的技术
继承是父类和子类之间共享属性和方法的机制。
继承关系中的子类将全部拥有父类的全部属性和方法,但只能用非私有化的属性和方法
同类型的对象,表现出的不同形态。(对象的多种形态)
绑定在编译时进行的,叫做静态绑定,动态绑定是在运行时进行的(动态绑定支持多态)
面向对象方法中的五大原则:
共同封闭原则:包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包产生影响,则将对该包中的所有类产生影响,而对于其他的包不造成任何影响。
共同重用原则:一个包中的所有类应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类。
面向对象分析是为了获得对应用问题的理解,其主要任务是抽取和整理用户需求并建立问题域精确模型。
面向对象设计是采用协作的对象、对象的属性和方法说明软件解决方案的一种方式,强调的是定义软件对象和这些软件对象如何协作来满足需求,延续了面向对象分析。
面向对象程序设计的实质:选用一种面向对象程序设计语言(OOPL):
特定的OOP概念一般是通过OOPL中特定的语言机制来体现的。
OOP现在已经扩展到系统分析和软件设计的范畴,出现了面向对象分析和面向对象设计的概念。
面向对象测试是根据规范说明来验证系统设计的正确性。
UML中有4中事物:
结构事物:结构事物是UML模型中的名词,通常是模型的静态部分,描述概念或物理元素。
行为事物:行为事物是UML模型的动态部分,它们是模型中的动词,描述了跨越时间和空间的行为。
分组事物:分组事物是UML模型的组织部分,是一些由模型分解成“盒子”。
注释事物:注释事物是UML模型的解释部分。这些注释事物用来描述、说明和标注模型的任何元素。
UML中有4种关系:依赖、关联、泛化和实现。
依赖:依赖是两个事物间的语义关系,其中一个事物(独立事物)发生变化会影响另一个事物(依赖事物)的语义。
关联:关联是一种结构关系,它描述了一组链,链是对象之间的连接。
聚合:部分和整体的生命周期不一致,整体消失了,部分仍然存在,部分可以脱离整体存在。
组合:部分和整体的生命周期一致,整体消失了,部分也消失了,部分不可以脱离整体存在。
泛化:泛化是一种特殊/一般关系,特殊元素(子元素)的对象可替代一般元素(父元素)的对象。子元素共享了父元素的结构和行为。
实现(了解):实现是类元之间的语义关系,其中一个类元指定了由另一个类元保证执行的契约。
类图(Class Diagram)展现了一组对象、接口、协作和它们之间的关系。
符号:
+
: public 公有的
-
: private 私有的
#
: protected 受保护的
~
: package 包的
类图用于对系统的静态设计视图建模。通常以下述3种方式之一使用类图:
对象图展现了某一时刻一组对象以及它们之间的关系,描述了在类图中所建立的事物的实例的静态快照。
对象图给出系统的静态设计视图或静态进程视图。
用例图展现了一组用例、参与者以及它们之间的关系。
一个用例执行的时候,可能会发生一些特殊的情况或可选的情况,这种情况就是这个用例的扩展用例。
参与者:参与者是与系统交互的外部实体。可能是使用者,也可能是与系统交互的外部系统、基础设备等。
用例:用例是从用户角度描述系统的行为,它将系统的一个功能描述成一系列的事件,这些事件最终对操作者产生有价值的观测结果。用例是一个类,它代表一类功能而不是使用该功能的某一具体实例。
之间的关系:
<<include>>
)(用例之间):一个用例包含另一个用例<<extend>>
)(用例之间):一个用例执行的时候,可能会发生一些特殊的情况或可选的情况,这种情况就是这个用例的扩展用例用例图用于对系统的静态用例视图进行建模。可用以下两种方式来使用用例图:
序列图(顺序图、时序图) :序列图是场景的图形化表示,描述了对象之间的时间顺序。
序列图用于展示系统中一个用例和多个对象的行为。
序列图有两个不同于通信图的特征:
序列图有对象生命线
序列图有控制焦点
通信图(协作图):通信图强调收发消息的对象的结构组织,在早期的版本中也被称作协作图。
通信图展现了对象之间的消息流及其顺序。
通信图有两个不同于序列图的特性:
状态图展现了一个状态机,它由状态、转换、事件和活动组成。
状态图展现了对象的状态转换及事件顺序
可以用状态图对系统的动态方面建模。当对系统、类或用例的动态方面建模时,通常是对反应型对象建模。
定义的状态主要有:初态(即初始状态)、终态(即最终状态)和中间状态。
三种标准事件:entry、exit、do
事件是在某个特定时刻发生的事情,它是对引起系统做动作或(和)从一个状态转换到另一个状态的外界事件的抽象。
转换包括两个状态(源状态,目标状态)
事件,监护条件,动作
事件触发转换(迁移)
活动(动作)可以在状态(迁移)内执行,也可以在状态转换时执行。
监护条件是一个布尔表达式。
活动图是一种特殊的状态图,它展现了在系统内从一个活动到另一个活动的流程。
活动图一般包括活动状态和动作状态、转换和对象。
通常有两种使用活动图的方式:
部署图是用来对面向对象系统的物理方面建模的方法,展现了运行时处理结点以及其中构件(制品)的配置。
部署图展现了系统的软件和硬件之间的关系,在实施阶段使用。
设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构。
设计模式基本要素:
/**
* 简单工厂模式
*/
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 使一个类的实例化延迟到其子类。
2)结构:创建型类模式
/**
* 工厂方法模式
*/
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 模式适用于
当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
1)意图
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
2)结构:创建型对象模式
/**
* 抽象工厂模式
*/
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 模式适用于
1)意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2)结构:创建型对象模式
/**
* 生成器模式
*/
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 模式适用于
1)意图
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
2)结构:创建型对象模式
/**
* 原型模式
*/
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 模式适用于
1)意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
2)结构:创建型对象模式
其中: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;
}
}
3)适用性 Singleton 模式适用于:
1)意图
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
2)结构
其中:
/**
* 适配器模式
*/
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 模式适用于:
1)意图
将抽象部分与其实现部分分离,使它们都可以独立地变化。
2)结构
/**
* 桥接模式
*/
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)适用性(了解)
1)意图
将对象组合成树型结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。
2)结构
其中:
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 模式下适用于:
1)意图
动态地给一个对象添加一些额外的职责。就增加功能而言,Decorator模式比生成子类更加灵活。
2)结构
其中:
/**
* 装饰器模式
*/
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 模式适用于:
1)意图
为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2)结构
其中:
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 模式适用于:
1)意图
运用共享技术有效地支持大量细粒度的对象。
2)结构
其中:
/**
* 享元模式 案例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模式适用于:
1)意图
为其他对象提供一种代理以控制对这个对象的访问。
2)结构
/**
* 代理模式
*/
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模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候,常见情况有:
1)意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
2)结构
其中:
/**
* 责任链模式
*/
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 模式适用于以下条件:
1)意图
将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2)结构
其中:
/**
* 命令模式
*/
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 模式适用于:
1)意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
2)结构
/**
* 解释器模式
*/
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模式适用于当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,以下情况效果最好:
1)意图
提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。
2)结构
其中:
/**
* 迭代器模式
*/
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 模式适用于:
1)意图
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
2)结构
其中:
/**
* 中介者模式
*/
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 模式适用于:
1)意图
在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。
2)结构
/**
* 备忘录模式
*/
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 模式适用于:
1)意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2)结构
其中:
/**
* 观察者模式
*/
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 模式适用于:
1)意图
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
2)结构
/**
* 状态模式
*/
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 模式适用于:
1)意图
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。
2)结构
/**
* 策略模式
*/
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 模式适用于:
1)意图
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2)结构
其中:
/**
* 模板方法模式
*/
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 模式适用于:
1)意图
表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。
2)结构
其中:
/**
* 访问者模式
*/
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²)等。
递归式时间复杂度:递归的次数 x 每次递归的时间复杂度
主方法。主方法也称为主定理,给出了求解以下形式的递归式的快速方法。
非递归:O(1) O(n) O(n²)
#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 个步骤:
#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;
}
#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;
}
#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;
}
一对一联系(1:1)。如班和班长之间是一对一联系。
一对多联系(1:n)。班和学生之间是一对多联系。
多对多联系(m:n)。课程和学生之间是多对多联系。
数据库系统在三级模式之间提供了两级映像:模式/内模式映像、外模式/模式映像。保证了数据库中的数据具有较高的逻辑独立性和物理独立性。
完整性规则保证用户对数据库做修改时不会破坏数据的一致性。
投影:投影运算是从关系的垂直方向进行运算,在关系R中选出若干属性列A组成新的关系,记作πA(R)
选择:选择运算是从关系的水平方向进行运算,是从关系R中选择满足给定条件的的元组,记作σF(R)
连接:连接运算是从两个关系R和S的笛卡儿积中选取满足条件的元组。
可以认为笛卡儿积是无条件连接,其他的连接操作认为是有条件连接。
外连接:外连接运算是连接运算的扩展,可以处理由于连接运算而缺失的信息。(p27集)
DDL(Data Definition Language,数据定义语言):用来定义数据库对象:数据库,表,列等。
关键字:CREATE
、DROP
、ALTER
等。
DML(Data Manipulation Language,数据操作语言):用来对数据库中表的数据进行增删改。
关键字:INSERT
、DELETE
、UPDATE
等。
DQL(Data Query Language,数据查询语言):用来查询数据库中表的记录。
关键字:SELECT
等。
DCL(Data Control Language,数据控制语言):用来定义数据库的访问权限和安全级别,及创建用户。
候选码中包含的属性称为主属性、不包含在候选码中的属性称为非主属性。若候选码多于一个,可以选定其中的一个为主码。
定义:若关系模式 R 每一个分量是不可再分的数据项,则关系模式 R 属于第一范式。
1NF可能存在的问题:
问题的原因是1NF中可能存在部分函数依赖。
定义:若关系模式 R∈1NF,且每一个非主属性完全依赖于码,则关系模式 R∈2NF。
当 1NF 消除了非主属性对码的部分函数依赖,则称为 2NF。
可能存在数据冗余和更新异常等问题。
2NF 消除了非主属性对码的传递函数依赖,则称为 3NF。
属于 3NF 的关系模式 R 可能存在主属性对候选码的部分依赖和传递依赖。
定义:R是一个关系模式,F是它的依赖集,R属于BCNF,当且仅当其F中的每个依赖的决定因素必定包含R的某个候选码。
BC范式已经消除了插入和删除异常
NF到4NF之间的转换关系:
范式 | 转换关系 |
---|---|
1NF | 每一个分量是不可再分的数据项 |
2NF | 1NF消除了部分函数依赖后满足2NF |
3NF | 2NF消除了非主属性对候选码的传递函数依赖后满足3NF |
BCNF | 3NF消除了主属性对候选码的部分和传递函数依赖后满足BCNF |
4NF | BCNF消除非平凡且非函数依赖的多值依赖后满足4NF |
新奥尔良法是目前公认的数据库设计方法,它将数据库设计分为以下几个阶段:
需求分析是后面几个阶段,逻辑结构设计、物理结构设计以及应用程序设计的依据。
需求分析将收集到的零碎的、局部的数据分析整理后,建立需求说明文档、数据字典和数据流程图。
需求分析阶段的成果:系统需求说明书、数据流图、数据字典、需求说明文档、各种说明性白表格
对需求分析阶段所得到的数据进行分类、聚集和概括,确定实体、属性和联系。
E-R 图之间的冲突
逻辑结构设计阶段的主要工作步骤包括:
事务是一个操作序列,这些操作“要么都做,要么都不做”。
事务和程序是两个不同的概念,一般一个程序可包含多个事务。
事务的ACID性质:
广播域 | 冲突域 | |
---|---|---|
物理层(集线器) | × | × |
数据链路层(交换机) | × | √ |
网络层(路由器) | √ | √ |
补充:
地址解析协议(ARP)和反地址解析协议(RARP)是网络层的一个重要的协议
ARP(地址解析协议):将IP地址转换为MAC地址(物理地址)。
IP到MAC地址的转换过程:
RARP(反地址解析协议):将MAC地址转换为IP地址,主要用于无盘工作站。
DHCP协议的功能和作用是:
DHCP客户端可以从DHCP服务器获得以下内容:
无效地址:
Windows无效地址:169.254.X.X
169.254.X.X是Windows系统在DHCP信息租用失败时自动给客户机分配的IP地址
Linux无效地址:0.0.0.0
协议名://主机名.域名.域名后缀.域名分类/目录/网页文件
组织模式 | 含义 | 地理模式 | 含义 |
---|---|---|---|
com | 商业机构 | cn | 中国 |
edu | 教育机构 | hk | 中国香港 |
gov | 政府机构 | mo | 中国澳门 |
mil | 军事部门 | tw | 中国台湾 |
net | 主要网络支持中心 | us | 美国 |
org | 上述以外组织 | uk | 英国 |
int | 国际组织 | jp | 日本 |
IPv6 128位地址空间、IPv4 32位地址空间。
Internet地址格式主要有两种书写形式:
IP地址:Internet中的主机地址实际上是用IP地址来唯一标识的。
IP地址有两种:
通常IP地址是指IPv4。
每个IPv4地址都由4个小于256的数字组成(每个数字8位,共32位),数字之间用.
分开,可分为5类:
补充:
在IPv4中,全0
代表的是网络,全1
代表的是广播。
IPv4能表示的地址个数为:2^32^≈40亿。
网络软件和路由器使用子网掩码来识别报文是仅存放在网络内部还是被路由转发到其他地方。
子网掩码是用来指明特定的IP地址中的网络号和主机号部分。子网掩码的格式与IP地址相同:
1
填上;0
填上。IPv6具有长达128位的地址空间,可以彻底解决IPv4地址不足的问题。
IPv6理论上能表示的地址个数:2^128^=3.4×10^38^
在想象得到的将来,IPv6的地址空间是不可能用完的。
流行的无线通信技术有WiFi、蓝牙等。其中,蓝牙覆盖范围最小、通信距离最短。
ipconfig命令的用法如下:
参数 | 说明 | 示例 |
---|---|---|
无参数 | 显示所有网络适配器的IP地址、子网掩码和缺省网关值 | ipconfig |
/all | 显示所有网络适配器的完整TCP/IP配置信息,包括DHCP服务是否已启动 | ipconfig /all |
/displaydns | 显示本地DNS内容 | ipconfig /displaydns |
/flushdns | 清除本地DNS缓存内容 | ipconfig /flushdns |
/registerdns | DNS客户端手工向服务器进行注册 | ipconfig /registerdns |
/release | DHCP客户端手工释放IP地址/释放所有连接 | ipconfig /release |
/renew | DHCP客户端手工向服务器刷新请求(重新申请IP地址)/更新所有适配器 | ipconfig /renew |
防火墙是建立在内外网络边界上的过滤封锁机制。
补充内容
包过滤防火墙
应用代理网关防火墙
状态检测技术防火墙
计算机病毒可以分为:
计算机病毒的特征包括:传播性、破坏性、隐蔽性、感染性、潜伏性、触发性等。
worm表示蠕虫病毒、Trojan表示特洛伊木马(秘密潜伏且能够通过远程网络进行控制的恶意程序)、Backdoor表示后门病毒、Macro表示宏病毒
木马软件: 冰河、X卧底
蠕虫病毒: 欢乐时光、熊猫烧香、红色代码、爱虫病毒、震网
补充病毒与木马的区别
【病毒】:
【木马】:
著作权(也称为版权):是指作者对其创作的作品享有的人身权和财产权。
人身权包括:
财产权(受时间限制)包括:
职务作品开发人员(软件设计师)只享有**署名权(不能被继承)**
题目形式:文字说明 + 两张数据流图 + 问题
数据流图的基本图形元素包括数据流、加工、数据存储和外部实体。
找实体名称
写法: E1 :病人 E2:护理人员 E3:医生
找数据存储名称
写法:D1:XX 表 XX 文件
D1:销售订单表 D2:库存表 D3:生产计划表 D 4:配方表 D5:采购订单表
题型:
三个解题方法
注意事项:数据流的起点和终点必须有一个是加工
答题格式:
数据库设计:
实体用矩形表示,通常矩形框内写明实体名。
例如职工与家属的联系,家属总是属于某职工的(在关系模式中需要依赖职工而存在),所以家属是弱实体。
超类和子类的转化
超类、子类实体都可以转换为一个关系,并将超类实体的主码加到子类实体中
联系用菱形表示,通常菱形框内写明联系名。 1:1
:
1:*
:
*:*
:只能转化成一个独立的关系模式,关系的码是多方实体的码构成的属性组
用椭圆形表示,并用无向边将其与相应的实体连接起来
关联:是一种结构关系,描述了一个组链,链是对象之间的连接
聚合:部分和整体的生命周期不一样,整体消失了,部分仍存在,部分可以脱离整体存在。
组合 :部分和整体的生命周期一样,整体消失了,部分也消失,部分不可以脱离整体存在。
泛化(继承) :父类泛化子类
实现:类实现一个接口
UML 类图
UML 用例图
<<extend>>
)和包含关系(<<include>>
),参与者和用例之间的关联关系,用例与用例以及参与者与参与者之间的泛化关系。
Qi列 = Qj列
|Qi行 - Qj行| = |Qi列 - Qj列|