[TOC]
计算机科学导论学习笔记 第 4 部分 计算机软件与算法 此部分包含第7 、8 、9 、10 章,包含了计算机操作系统、问题求解算法、程序设计语言之旅、软件工程等相关知识,加深我们对开发的认识,为后续开发打下一个基础。
原文地址: https://mp.weixin.qq.com/s/D48BsQABLPZCI7riqPvdCA
第 9 章 程序设计语言 9.1 语言演化 计算机语言是指编写程序时,根据事先定义的规则(语法)而写出的预订语句集合。
计算机语言已经度过了从机器语言,到汇编语言,到高级语言的演化。
1) 机器语言
早期,计算机唯一的程序设计语言就是机器语言
,每台计算机都有其自己的机器语言,它由0
和1
二进制数组成,在电气元件中分别表示关和开
电路。
缺点:
严重依赖计算机,不同计算机机器不能执行已编写运行的机器语言。
使用机器语言编写程序单调、乏味,还易错。
weiyigeek.top-两个数相加使用机器语言代码表示图示
2) 汇编语言
汇编语言是由带符号或助记符(符号语言
)的指令和地址组成,目的是为了替代机器语言。
汇编语言代码通过汇编程序
将其翻译成为机器语言,其缺点是仍然需要程序员在硬件上花费大部分精力,并且由于每条机器指令都必须单独编码,则效率比较低下。
常用助记符:
[TOC]
计算机科学导论学习笔记 第 4 部分 计算机软件与算法 此部分包含第7 、8 、9 、10 章,包含了计算机操作系统、问题求解算法、程序设计语言之旅、软件工程等相关知识,加深我们对开发的认识,为后续开发打下一个基础。
原文地址: https://mp.weixin.qq.com/s/D48BsQABLPZCI7riqPvdCA
第 9 章 程序设计语言 9.1 语言演化 计算机语言是指编写程序时,根据事先定义的规则(语法)而写出的预订语句集合。
计算机语言已经度过了从机器语言,到汇编语言,到高级语言的演化。
1) 机器语言
早期,计算机唯一的程序设计语言就是机器语言
,每台计算机都有其自己的机器语言,它由0
和1
二进制数组成,在电气元件中分别表示关和开
电路。
缺点:
严重依赖计算机,不同计算机机器不能执行已编写运行的机器语言。
使用机器语言编写程序单调、乏味,还易错。
weiyigeek.top-两个数相加使用机器语言代码表示图示
2) 汇编语言
汇编语言是由带符号或助记符(符号语言
)的指令和地址组成,目的是为了替代机器语言。
汇编语言代码通过汇编程序
将其翻译成为机器语言,其缺点是仍然需要程序员在硬件上花费大部分精力,并且由于每条机器指令都必须单独编码,则效率比较低下。
常用助记符:1 2 3 4 LOAD : 读取寄存器中数据。 STORE : 将数据存储到寄存器中。 ADDI : 将两个寄存器数据相加。 HALT : 停止运行。
weiyigeek.top-使用汇编语言表示两整数相加的过程
3) 高级语言
高级语言的发展是为了解决(摆脱
)汇编语言开发的低效、繁琐的细节
,让程序员可以从关注计算机转到关注要解决的问题,即将精力集中在应用程序上,而不是计算机结构的复杂性上。
高级语言可以将编写代码程序移植到不同计算机操作系统中执行,同样它也需要经过解释或者编译
流程将其转为机器语言,所以在高级语言又分解释型高级语言
和编译型高级语言
。
例如,使用Go语言演示两个数相加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport "fmt" func main () { var a int var b int var result int a = 127 b = 128 result = a + b fmt.Println(result) }
输出结果:255
9.2 语言翻译 前面提到,为了在计算机上运行程序,程序需要被翻译成它要运行在其他的计算机的机器语言。
高级语言程序 :被称为源程序
目标程序: 被翻译成的机器语言程序
(1) 编译 编译程序通常把整个源程序翻译成目标程序。
(2) 解释 解释器会把源程序翻译成目标程序,而解释是指把源程序中的每一行翻译成目标程序中相应的行,并执行它的过程。
在解释中的两种趋势:
解释的第一种方法
在Java语言之前的有些解释式语言(如BASIC和APL)使用一种称为解释的第一种方法的解释过程,因为缺少其他任何的名字,所以称为解释的第一种方法。在这种解释中,源程序的每一行被翻译成被其使用的计算机上的机器语言,该行机器语言被立即执行。如果在翻译和执行中有任何错误,过程就显示消息,其余的过程就被中止。程序需要被改正,再次从头解释和执行。第一种方法被看成是一种慢的过程,这就是大多数语言使用编译而不是解释的原因。
解释程序的第二种方法
随着Java的到来,一种新的解释过程就被引入了,Java语言能向任何计算机移植,其为了取得可移植性,源程序到目标程序的翻译分成两步进行编译
和解释
。
Java源程序首先被Java编译器编译
,创建Java的字节代码,字节代码看起来像机器语言中的代码,但不是任何特定计算机的目标代码,它是一种虚拟机的目标代码,该虚拟机称为Java虚拟机或JVM
,字节代码然后能被任何运行JVM模拟器的计算机编译或解释,也就是运行字节代码的计算机只需要JVM模拟器,而不是Java编译器。
(3) 翻译 编译和解释的不同在于,编译在执行前翻译整个源代码,而解释一次只翻译和执行源代码中的一行(因此效率低下
)。
但是两种方法都遵循图中显示的相同的翻译过程:
weiyigeek.top-源代码翻译过程
词法分析器
: 一个符号接一个符号地读源代码,创建源语言中的助记符表。
例如,5个符号w、h、i、1、e被读入,组合起来就形成了C、C++或Java语言中的助记符while.
语法分析器
: 一组助记符,找出指令。
例如,语法分析器使用助记符“X”、”=”、“0” 创建C语言中的赋值语句“x=0”
语义分析器
: 检查语法分析器创建的句子,确保它们不含有二义性,而计算机语义通常情况下是无二义性的,意味着这一步骤或者是在翻译器中被省略。
代码生成器
: 将每条指令将转化为一组程序将要在其上运行的计算机的机器语言。
9.3 编程模式 当下,计算机语言按照它们使用的解决问题的方法来分类,因此模式是计算机语言看待要解决问题的一种方式。
计算机语言可分为四种模式:过程性、面向对象、函数式和声明式
。
面向过程:FORTRAN、COBL、BASIC、C 语言、Pascal、Ada
面向对象:Smalltalk、C++、Visual、Basic、C#、Java、Python
函数式:LISP、Scheme
声明式:Prolog
(1) 过程式模式 在该模式中,我们把程序看成是操纵被动对象的主动主体。例如,我们在日常生活中遇到许多被动对象石头、书、灯等, 一个被动对象本身不能发出一个动作,但它能从主动主体接收动作。
在该模式下的程序就是主动主体,该主体使用称为数据或数据项的被动对象, 作为被动对象的数据项存储在计算机的内存中,程序操纵它们, 为了操纵数据主动主体(程序)发出动作,称之为过程。例如,考虑一个打印文件内容的程序,为了能被打印,文件需要存储在内存中(或一些像内存一样的寄存器中)。
文件是一个被动对象或一个被动对象集合, 对象(文件)是一个能接收print动作或其他一些动作(如删除、复制等)的独立实体。 打印(print
)过程通常包括了需要告诉计算机如何打印文件中每一个字符的所有动作,它是是编写的一个独立实体,程序只是触发它。 即为了避免每次需要打印文件时都编写一个新过程,我们可编写一个能打印任何文件的通用过程,当过程被调用触发时,我们可以传递实际要打印的文件名给过程,这样便使得一个过程调用两次,分别打印不同的文件。
如果我们考虑过程和被作用于的对象,那么过程式模式的概念就变得更为简单,且容易理解。这种模式的程序由三部分构成:对象创建部分、一组过程调用和每个过程的一组代码
。有些过程在语言本身中已经被定义, 我们可通过组合代码来建立新的过程。
例如,下图中显示了程序如何能调用不同的预定义过程,打印或删除不同的目标文件,以及过程式程序的三个组成部分。
weiyigeek.top-过程式概念与组成部分
常见的过程式语言
FORTRAN ( FORmula TRANsIation
) :它是第一代高级语言,由Jack Backus 领导下的一批IBM工程师所设计,于1957年变成商用的,在50年后的今天它仍然是科学或工程应用中的理想语言。
语言版本:FORTRAN. FORTRAN U、FORTRAN IV, FORTRAN 77、FORTRAN 99 和HPF(高性能FORTRAN),以及最新版本(HPF) 用于高速多处理器计算机系统。
语言特点:
高精度算法。
处理复杂数据的能力。
指数运算(a^b)
COBOL (COmmon Business-Oriented Language
): 由一批计算机专家在美国海军的Grace Hopper指导下设计出来,作为商业编程语言使用。
语言特点:
快速访问文件和数据库。
快速更新文件和数据库。
生成大量的报表。
界面友好的格式化的输出。
Pascal : 由Niklaus Wirth于1971年在瑞士的苏黎世发明,根据17世纪发明Pascaline计算器的法国数学家、哲学家Blaise Pascal来命名,尽管Pascal成为学术中最流行的语言,但它从未在工业中达到同等流行的程度,现在的过程化语言归功于该语言(发展)。
设计目标:通过强调结构化编程方法来教初学者编程。
C 语言:由贝尔实验室的Dennis Ritchie在20世纪70年代初期发明的,最初用于编写操作系统和系统软件(UNIX操作系统的大部分是用C编写),当前 C 语言仍然是效率最高的语言,针对操作系统、以及嵌入式开发必学。
语言特点:
有一个结构化的高级编程语言应有的所有高级指令,使程序员无需知道硬件细节。
具有一些低级指令,使得程序员能够直接、快速地访问硬件。相对于其他高级语言,C更接近于汇编语言,这使得它对系统程序设计员来说是一种好语言。
是非常有效的语言,指令短。这种简洁吸引了想编写短程序的程序员。
Ada :其命名是为了纪念世界上第一位程序员[阿达·洛芙莱斯](Ada Lovelace
),旨在整合美军事系统中运行着上百种不同的程序设计语言。
语言特点:
(2) 面向对象模式 该模式处理活动对象,而不是被动对象,通常此类对象只需要接收合适的外部刺激来执行其中的一个动作。例如,我们生活中遇到的许多活动对象汽车、自动门、洗盘机等。
在面向对象模式中的文件能把所有的被文件执行的过程(在面向对象模式中称为方法)打包在一起,这些过程有打印、复制、删除等,仅仅向对象发送相应请求(打印、复制、删除等
),文件就会进行相应操作。
此处比较过程式模式和面向对象模式
,可以看出过程式模式中的过程是独立的实体
, 但面向对象模式中的方法是属于对象领地的
。
weiyigeek.top-面向对象模式的概念
类 (Class)
说到面向对象就不得不提到类(Class)
, 通常相同类型的对象(如文件)需要一组方法,方法显示了这类对象可操作的描述(属性
)或者动作(方法
),例如 C++、Java和C# (读作”C sharp”)等面向对象语言使用称为类的单元
面向对象语言特点:
属性与方法:在该类语言中,通常我们会在类中定义对象的属性和方法,例如 动物(Animal)类包括 的名称、外观、颜色属性,以及动物吃食物的方法。
继承性:即一个对象能从另一个对象继承,便于为已存在类的添加一些新的特性。例如,Cat 动物猫,继承 Animal 类,则可以继续添加喜欢的食物属性,以及猫吃🐠的方法。
多态性:指我们可以定义一些具有相同名字的操作,而这些操作在相关类中做不同的事情,例如,我们定义了两个类:矩形(rectangle
)和 圆(circular
),都是从几何形状类继承下来的,我们定义名字都为area的两个操作,一个在矩形类中;一个在圆类中,它们分别计算矩形或圆的面积。
例如,此处以Go语言为例演示面向对象语言类的使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package mainimport "fmt" type Animal struct { name string } func (a *Animal) voice (v string ) { fmt.Printf("我是动物,我叫 %v, 我会叫 %s," , a.name, v) } type Dog struct { eat string *Animal } func (d *Dog) love () { fmt.Printf("狗狗喜欢吃的食物是 %v.\n" , d.eat) } type Cat struct { eat string *Animal } func (c *Cat) love () { fmt.Printf("猫猫喜欢吃的食物是 %v.\n" , c.eat) } func main () { d1 := &Dog{ Animal: &Animal{ name: "小黄" , }, eat: "bone" , } d1.voice("汪汪.汪汪." ) d1.love() c1 := &Cat{ Animal: &Animal{ name: "小白" , }, eat: "fish" , } c1.voice("喵喵.喵喵." ) c1.love() }
执行结果:
1 2 我是动物,我叫 小黄, 我会叫 汪汪.汪汪.,狗狗喜欢吃的食物是 bone. 我是动物,我叫 小白, 我会叫 喵喵.喵喵.,猫猫喜欢吃的食物是 fish.
常见的过程式语言
C++ : 是由贝尔实验室Bjame Stroustrup等人开发出来的,是比C语言更高级的一种计算机编程语言,它使用类来定义相似对象的通用属性以及可以应用于它们本身的各种操作。
语言特点:C++语言的设计遵循三条基本原则特性封装、继承和多态
。
Java:当前后端开发占有率最高的语言之一,由Sun Microsystems公司开发的,它在C和C++的基础上发展而来,但是C++ 的一些特性(如多重继承等)从语言中被移除,从而使Java更健壮。在Java中的程序可以是一个应用程序
也可以是一个小程序
,应用程序是指一个可以完全独立运行的程序
,小程序则是嵌入在超文本标记语言
。
语言特点:
程序的执行时,将构建一个类并把它传给编译器,由编译器来调用类的方法。
许多线程执行(几行代码同时执行),线程是指按顺序执行的动作序列。
(3) 函数式模式 该模式下程序被看成是一个数学函数,函数是把一组输入映射到一组输出的黑盒子。例如,求和可以被认为是具有n个输入和1个输出的函数,该函数实现n输入值相加得到总和并最终输出求和结果。
函数式语言主要实现下面的功能:
例如,定义一个称为first的原始函数,由它来完成从一个数据列表中抽取第一个元素的功能。再定义另一个函数rest,由它完成从一个数据列表中抽取出除第一个元素以外的所有元素,通过两个函数的组合使用,可以在一个程序中定义一个函数来完成对第三个元素的抽取。
weiyigeek.top-函数式语言中的函数
常见的函数是语言:
LISP(LISt Programming
):表处理解释语言是20世纪60年代早期由麻省理工学院科研小组设计开发的,它是一种把表作为处理对象的语言。
Scheme:由麻省理工学院在20世纪70年代早期开发的,此时表处理解释语言没有统一标准化,不久之后就有许多不同的版本流传于世,该语言定义了一系列原始函数来解决问题,函数名和函数的
输入列表写在括号内,结果是一个可用于其他函数输入的列表。
例如,有一个函数car,用来从列表中取出第一个元素,第二个函数cdr用来从列表中取出除第一个元素以外的所有元素。
两个函数如下:
car 2 3 5 7 9 => 2
cdr 2 3 5 7 9 => 3 5 7 9
现在可通过该组合来完成从列表中取出第三个元素的函数。
(car (cdr (cdr 2 3 5 7 9 ) ) ) => 取 5
(4) 声明式模式 也称为说明式,该模式依据逻辑推理的原则响应查询,它是在由希腊数学家定义的规范的逻辑基础上发展而来的,并且后来发展成为一阶谓词演算(first-order predicate calculus)
。逻辑推理以推导为基础,逻辑学家根据已知正确的一些论断(事实),运用逻辑推理的 可靠的准则推导出新的论断(事实)。
例如,逻辑学中著名的推导原则如下:
weiyigeek.top-A->B-C
说明式语言
Prolog (PROgramming in LOGic
):它是最著名的说明性语言,它是由法国人A.Colmerauer
于1972年设计开发的,Prolog中的程序全部由事实和规则组成。
9.4 共同概念 此节中,通过对一些过程式语言的快速浏览,发现其共同概念,并且其中某些概念对大多数面向对象语言也适用
,因为创建方法时面向对象模式使用过程式模式。
(1) 标识符 所有计算机语言的共同特点之一就是都具有标识符,标识符允许给程序中对象命名,即对象的名称
.
例如,计算机中每一个数据都存储在一个唯一的地址中,我们可以数据对象命名,然后给出数据的名字就可以让编译器去跟踪数据实际存放的物理地址。
(2) 数据类型 其定义了一系列值及应用于这些值的一系列操作,每种数据类型值的集合称为数据类型的域,而大多数语言都定义了两类数据类型,即简单数据类型
和复合数据类型
。
1) 简单数据类型
该类型有时又称为原子类型、基本类型、标量类型或内建类型
,是不能分解成更小数据类型的数据类型,强制性语言已经定义一些简单数据类型:
整数类型(int):是不包括小数部分的完整的数。整数的取值范围依赖于语言。有些语言支持多种整数大小。
实数类型(float):是带小数部分的数字。
字符类型(char):是被语言使用的潜在字符集中的符号,例如,ASCII或Unicode,占 1 B空间大小。
布尔类型(boolean):是只取两个值(真或假)的数据类型。
2) 复合数据类型
该类型是一组元素,其中每个元素都是简单数据类型或复合数据类型(这是递归定义),大多数语言定义了如下的复合数据类型:
1 2 3 4 5 int array[10] = {1,2,3,4,5,6,7,8,9,10}; list1 = ['唯一极客' , 2, 'weiyigeek' , [1, 3, 4]]
3) 变量声明与初始化
变量是存储单元的名字,数据项在内存中可能占据多个地址,名字(作为地址的替代)使程序员从地址中解放出来,只需在程序如何执行的层次上考虑。
变量声明:大多数过程式语言和面向对象语言要求变量在使用前被声明,声明警告计算机被赋予名字和类型的变量将在程序中使用,要求计算机预留出相应的存储区域。
变量初始化:虽然存储在变量中的数据值在程序执行过程中可能改变,但大多数过程式语言允许变量在它声明时进行初始化
,初始化就是在变量中存储一个值(实际上是存储在寄存器中)。
1 2 3 4 5 6 7 8 9 10 char c; int number; double result; char c='a' ; int number=1024; double result=256.128;
4) 字面值
字面值是程序中使用的预定义的值,在大多数程序设计语言中,可以有整数、实数、字符和布尔字面值,还可以有字符串字面值,为了把字符和字符串字面值从变量名和其他对象中区分开,大多数语言要求字符字面值被括在单引号中,如’A’,而字符串字面值被括中双引号中,如”Anne”。
例如,当半径存储在变量r中,需要计算圆的面积时,可以使用表达式π x r2其中π(pi)的近似值就是被用作字面值,此处以Go语言为例。1 2 3 4 5 6 7 8 9 10 11 package mainimport ( "fmt" "math" ) func main () { fmt.Printf("%f\n" , math.Pi) fmt.Printf("%.2f\n" , math.Pi) fmt.Printf("%f\n" , math.Pi*math.Pow(4 , 2 )) }
执行结果为:
5) 常量
在程序中出了字面值以外不能在运行时被改变的量,称其为常量。
大多数编程语言定义常量(类似于变量)是一个可以存储值的名字的位置,但不同与变量的是其在声明初始化(需指明类型)后其值便不能够被改变。
1 2 const float flagNum = 10.24
6) 输入输出
几乎所有的程序都需要输入和(或)输出数据,大多数程序设计语言使用一些预先定义好的函数完成输入和输出。
输入:数据或者通过语句或者通过预先定义的函数来完成输入。
输出:数据或者通过语句或者通过预先定义的函数来完成输出。
1 2 3 4 5 6 7 8 9 #include <stdio.h> void main () { int a,b,c; printf ("input a,b,c\n" ); scanf ("%d%d%d" ,&a,&b,&c); printf ("a=%d,b=%d,c=%d" ,a,b,c); }
C 语言格式字符说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 %a,%A 读入一个浮点值(仅C99有效) %c 读入一个字符 %d 读入十进制整数 %i 读入十进制,八进制,十六进制整数 %o 读入八进制整数 %x,%X 读入十六进制整数 %c 读入一个字符 %s 读入一个字符串,遇空格、制表符或换行符结束。 %f,%F,%e,%E,%g,%G 用来输入实数,可以用小数形式或指数形式输入。 %p 读入一个指针 %u 读入一个无符号十进制整数 %n 至此已读入值的等价字符数 %[] 扫描字符集合 %% 读%符号
7) 表达式
表达式是由一系列操作数
和运算符
简化后的一个单一数值,例如 3 + 2 - 5 = 0
操作数:用于接收一个运算符的动作,对于任何一个运算符可能有1、2或更多个操作数。
运算符:是用来完成一个动作的特定语言的语法记号。
算数运算符:即常见的加、减、乘、除等符号。
关系运算符:即用于比较两个数的大小关系。
逻辑运算符:即判断逻辑值(True、False)组合后的新值。
weiyigeek.top-运算符
(3) 语句 每条语句都使程序执行一个相应的动作,它被直接翻译成一条或多条计算机可执行的指令。
赋值语句:即给变量赋值,例如 C、C++和Java使用 “=” 赋值,其他语言 Go 、Ada、Pascal 则使用 := 来赋值。
复合语句:即包含零个或多个语句的代码单元,其被称为块,例如,Javascript 中的代码块。
控制语句:即我们在数据算法中提到的三种结构顺序、选择、循环
。
1 2 3 4 5 6 7 8 // 选择 if (条件) ... else ...switch (条件) ... case ... // 循环 while (条件) ...for (int i = 0; i < 0; i++) {}do .... while (条件)
(4) 子程序 子程序(称为函数更贴切
)的概念在过程式语言中极其重要,在面向对象语言中的作用要少些。
子程序(即理解为函数
)使程序变得更结构化,更便于协同开发,帮助检査错误,完成特定任务的子程序能一次编写多次调用,就像在编程语言中的预定义过程一样。
局部变量:即变量的作用域,在子程序内部定义的变量,其声明周期随着函数调用而产生,结束而销毁。
参数:通常我们需要给子程序传递参数,在主程序中称为实际参数,在子程序中称为形式参数,所以在参数传递时分为传之
和传引用两种方式
。
传值参数:主程序和子程序创建两个不同的对象(变量),在程序中创建的对象属程序,在子程序中创建的对象属于子程序,即传入到子程序中实际参数是独立的,在子程序内部处理加工的后的参数不会影响改变
传入的变量值。
传引用参数:传引用被设计来允许子程序改变主程序中变量的值,在程序向子程序传递参数变量(实际上它是内存的地址)被主程序和子程序共享,即在子程序内部处理加工的后的参数会影响改变
传入的变量值。
返回值:子程序(函数
)通常是返回一个或者多个值。
实现:子程序概念在不同的语言中被不同地实现,在C和C++中子程序被实现为函数
此处,以C语言为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <stdlib.h> int value_swap (int a, int b) { int tmp = 0 ; if (a > b) { tmp = a; a = b; b = tmp; } printf ("子程序(函数内部)a = %d , b = %d \n" ,a , b); return tmp; } void reference_swap (int *a, int *b) { int tmp = 0 ; if (a > b) { tmp = *a; *a = *b; *b = tmp; } printf ("子程序(函数内部)a = %d , b = %d\n" ,*a , *b); printf ("a 变量地址 %p , b 变量地址 %p\n" , a , b); } int main () { int a = 8 ; int b = 2 ; printf ("主程序 a = %d , b = %d \n" ,a , b); value_swap(a, b); printf ("经过值传递 value_swap 子程序(函数)后,主程序 a = %d , b = %d \n\n" ,a , b); printf ("主程序 中 a 变量地址 %p , b 变量地址 %p\n" , &a , &b); reference_swap(&a,&b); printf ("经过值引用 reference_swap 子程序(函数)后,主程序 a = %d , b = %d \n" ,a , b); }
执行结果:
1 2 3 4 5 6 7 8 主程序 a = 8 , b = 2 子程序(函数内部)a = 2 , b = 8 经过值传递 value_swap 子程序(函数)后,主程序 a = 8 , b = 2 主程序 中 a 变量地址 0x7ffd748ca05c , b 变量地址 0x7ffd748ca058 子程序(函数内部)a = 2 , b = 8 a 变量地址 0x7ffd748ca05c , b 变量地址 0x7ffd748ca058 经过值引用 reference_swap 子程序(函数)后,主程序 a = 2 , b = 8
第 10 章 软件工程 此节介绍软件工程概念以及软件生命周期为起点,以及开发过程中的两个模型(瀑布模型和增量模型
)。
在1969年第一届国际软件工程会议,恰巧是第一台计算机诞生30年之际,定义了软件工程是建立在利用合理的工程方法和原则来获得在真实机器上工作的可靠软件。
10.1 软件生命周期 (1) 生命周期概念 描述:软件生命周期是软件工程的基本概念,软件和其他的产品一样,周期性地重复着一些阶段。
weiyigeek.top-软件生命周期
(2) 开发过程模型 在软件生命周期中,开发过程包括4个阶段:分析、设计、实现和测试
,并且有多种模型,此处讨论最常见的两种模型,即瀑布模型和增量模型
。
瀑布模型 : 它是一种非常流行的模型,开发过程只有一个方向的流动。意味则前一个阶段结束,才能开始后面一个阶段。
例如,整个工程的分析阶段应该在设计阶段开始前完成,整个设计阶段应该在实现阶段开始前完成。
优点:在下一个阶段开始前每个阶段已经完成,在测试阶段整个系统整体功能已经完成。
缺点:问题定位难,如果过程中中有一部分有问题,则必须检查整个过程。
增量模型 :它是企业中最常用的模型,由开发者根据初始需求进行开发,后续在由需求是在进行开发,这就是我们常说的模块化开发。
weiyigeek.top-瀑布模型与增量模型
10.2 分析阶段 整个开发过程始于分析阶段,此阶段生成规格说明文档
,即说明了软件要做什么
,它使用两种独立的方法,其依赖于实现阶段是使用 过程编程还是对象编程
(1) 面向过程分析 1) 数据流图 : 显示了系统中数据的流动,使用4种符号来表示。
方形盒: 表示数据源或数据目的 带圆角的矩形: 表示过程(数据上的动作) 末端开口的矩形: 表示数据存储的地方 箭头表示: 数据流
2) 实体图 :实体关系图是分析阶段使用的另一个建模工具,此图主要用于数据库的设计。
3) 状态图 : 提供了另外一种有用的工具,其通常用于当系统中的实体状态在响应事件时将会改变的情况下。
weiyigeek.top-数据流图与状态图
(2) 面向过程分析 1) 用例图 : 系统用户视图,它显示了用户与系统间的交互,常常使用四种组件表示,即系统、用例、动作者和关系
。
系统(用矩形表示)执行功能。 系统中的行动(圆角的矩形表示)由用例显示。 动作者:是使用系统的某人或某事。 关系:使用线条联系动作者与行动,但它们并不需要表示人类。
2) 类图 :经过分析下一步就是创建系统类图,主要是考虑系统涉及的实体。
3) 状态图 :在类图完成之后,就可以为类图中的每个类准备状态图,其与面向过程分析中的状态图相同。
weiyigeek.top-用例图与类图
10.3 设计阶段 设计阶段定义系统如何完成在分析阶段所定义的需求,即到底怎么做
,此阶段中系统所有的组成部分都被定义。
(1) 面向过程设计 在面向过程设计中,即要设计过程也要设计数据,并且整个系统被分解成一组过程或模块
。
1) 结构图 :主要用于说明模块间的关系,例如图中的 10.8。
2) 模块化 :将大项目分解成较小的部分,以便能够容易理解和处理,即意味着将大程序分解成能互相通信的小程序,通常在代码开发时要求低耦合
和高内聚
。
(2) 面向对象设计 在面向对象设计中设计阶段,通过详细描述类(Class)的细节,例举出其对象的属性以及方法动作的细节。
weiyigeek.top-结构图
10.4 实现阶段 此阶段在瀑布模型中,通常是在设计阶段完成之后,其主要为面向过程设计中的模块编写程序
或者编写程序单元
,换言之,根据需求开始写代码🤓。
(1) 语言选择 通常在企业中都有相应的技术开发栈,例如 C 系列、Java 系(当前最多)、Go 系(次之)、Python 系,对应不同的开发需求、侧重点选择一种开发语言,使得开发周期变短。
(2) 软件质量 高质量的软件系统是一个能满足用户需求、符合组织操作标准和能高效运行在为其开发的硬件上的一个软件。
软件质量能够划分成三个广义的度量∶可操作性、可维护性和可迁移性
。
1) 可操作性:涉及系统的基本操作,具有有多种度量方法准确性、高效性、可靠性、安全、及时性和适用性
。
2) 可维护性:以保持系统正常运行并及时更新为参照,具有有多种度量方法可变性、可修正性、适应性,可测试性
3) 可迁移性:指把数据和(或)系统从一个平台移动到另一个平台并重用代码的能力,有有多种度量方法重用性、互用性、可一移植性
weiyigeek.top-软件质量
10.5 测试阶段 此阶段主要是在上线前尽可能发现错误,意味着良好的测试策略能发现最多的错误,通常有白盒测试与黑盒测试两种。
(1) 白盒测试 或叫玻璃盒测试,即内部开发测试人员,知道或者拿到软件分析文档,设计文档,以及有开发的源程序代码
, 程序就像玻璃盒子,其中的每件事都是可见的。
白盒测试需要保证至少满足下面4条标准:
白盒测试有多种测试方法,其中最常见是基本路径测试
和控制结构测试(逻辑测试)
。
基本路径测试 :由Tom McCabe提出的,它是一种软件中每条语句至少被执行一次的方法。
控制结构测试 :它比基本路径测试更容易理解并且包含基本路径测试,例如下方不同类的测试。
条件测试:用来检査是否所有的条件都被正确设置。
数据流测试:用来检査被用在赋值语句左边的变量的值。
循环测试:用来检查循环的正确性。
(2) 黑盒测试 即我们在不知道其程序分析文档、设计文档以及拿不到程序源代码时进行的测试,通常在业务上线前需要进行黑盒的安全渗透测试,换言之,程序就像看不见内部的黑盒。
穷尽测试 :在输入域(路径、输入、传参出)中的使用所有可能的值去测试软件。
随机测试 :在输入域的值的子集来测试,子集选择的方式(值在输入域上的分布)是非常重要的。
边界值测试 :当遇到边界值时错误经常发生,即我们常说的缓冲区溢出,可能会对代码程序致命的错误。
10.6 软件文档 企业内部中在开发初始阶段便有许多开发设计文档,随着业务的迭代也有自己的Bug管理文档,所以说软件的正确使用和有效维护离不开文档,所以文档是一个持续过程。
通常软件有三种独立的文档:用户文档、系统文档和技术文档
。
用户文档 :即用户手册的文档,它告诉用户如何一步步地使用此软件。
系统文档 :即定义软件本身,其目的是为了让原始开发人员之外的人能够维护和修改软件包(接盘侠 😳)。
在分析阶段,收集的信息应该仔细地用文档记录
在设计阶段,最终版本中用到的工具必须记录在文档中。
在实现阶段,代码的每个模块都应记录在文档中。
在测试阶段,对最终产品使用的每种测试,连同它的结果都要记录在文档中。
技术文档 : 即软件系统的安装部署,通常由专业的技术人员进行参考。