接下来通过一个实际的例子
给大家展示典型的软件开发流程
应该怎么去操作
从软件工程这个角度来讲
真实的开发程序实际上要通过
需求分析、概要设计、详细设计、
编码实现、系统测试
这样的五个步骤才能完成
如果我真是开发工业强度的程序
没有这些流程
程序的开发实际上是非常非常困难的
软件工程第一个步骤就是要需求分析
要确定软件需要解决什么问题
在这里面起决定因素的实际上是人
软件开发人员需要和用户
进行深入交流
确定整个程序的输入和输出
以及其它附加信息
从设计程序这个角度上来讲
不要轻视任何问题
因为哪怕是最简单的一个问题
用计算机语言来实现它的时候
其实都是非常非常复杂的
有了需求分析以后
实际上就明确了这个程序要解决什么
要输出什么
然后才能够提供我们的方案
从方案设计这个角度来讲
分成两个部分
一个是概要设计 一个是详细设计
概要设计就是给出
整个程序设计的整体方案
形成高层模块的划分
有了概要设计 有了总体方案
那么就可以向总体方案中填充细节
包括每一个模块的输入、输出和算法
都要在概要设计里面完成
有了概要设计之后
其实已经明确了程序中
要设计什么样的函数
设计什么样的模块
如果具体到某一个特定的函数的话
那么每一个函数输入是什么
输出是什么 算法是什么
所有的信息理论上都应该完成
有了它就可以很容易地编写程序代码
程序全部编写完成之后
不能现在就交付 必须要测试
你得保证程序的健壮性、稳定性
和正确性
所有的工作都要通过系统测试来完成
画一个图 从需求分析阶段开始
接下来是方案设计阶段、
编码实现阶段、系统测试阶段
流程一步一步的来
走到方案设计阶段的时候
有可能出现这样的情况
发现方案设定不清晰
原因不是方案没设计好
而是需求分析没做好
这个时候可能就要回过头来
重新去做需求分析
或者补充一些需求
还有一种情况
到了编码阶段发现方案没做好
重新来修改方案也有可能
到方案修改过程中
又发现需求分析分析不好
又要回去重新做需求分析
有没有可能 还是有可能的
所以你看 整个软件开发流程
需求分析、方案设计、编码实现
最后是系统测试
每一个过程都有可能会产生一种反馈
修改原来的设计 原来的分析
原来的实现
形成一个螺旋式的开发流程
这种情况就是最常见的软件开发过程
通过具体的例子向同学们展示
我们怎么从需求分析、方案设计
到编码实现和系统测试
这个程序叫我猜！我猜！我猜猜猜！
题目很简单
编程实现一个简单的猜测价格的游戏
假设我有一件东西
我已知道它的最高价格和最低的价格
然后让游戏参与者就在这个范围内猜
它的实际价格是什么
当然你有一个猜测次数的限制
要写程序来模拟这个过程
先从需求分析开始
我们就要和提出任务那一方进行讨论
别人让你写程序
都会给你提供一系列需求
比如讲游戏运行前
首先应该向游戏参与者
介绍这个游戏的功能
这个叫需求A 然后是需求B
首期这个工程不需要解决游戏难度问题
希望游戏尽快能够跑起来
然后他会说 如果有一个需求C
在每一个游戏回合结束的时候
最后那个玩家啊 你得让它选
继续玩下一局还是不玩了
如果用户说我不玩了 游戏应该结束
如果用户说我继续玩
那么就应该继续玩下去
然后是需求D
要记录游戏参与者的信息
记录这个玩家玩了几个回合
赢了几个回合
我要能够统计这个信息
最后在用户退出游戏的时候
输出胜率是多少
给他一个明确的结论信息
做这个需求分析的时候你就会发现
一开始跟他了解
整个程序需求的时候
跟你说了需求A、B、C、D、E
五个需求
这里边有很多地方都没有明确
什么叫最简单情形啊
说“我这个程序一开始不用考虑难度
你给我做简单一点”
这个程序能写吗 不能写的
你要和用户再次沟通 要明确这个东西
我们的物品最低价100块 最高价200块
用户最多只能猜6次
物品实际价格在100块钱到200块钱之间
随机生成一个
如果游戏者猜想的价格
比实际价格高了
你就提示他 价格高了
如果用户猜测价格
比它的实际价格又低了
你就提示他低了
这样的话最后玩家要能够有的放矢
修改他的价格
这就是细化出来的四个需求
想到这个地方啊
你的用户就可能一拍脑门
“哎呦 刚才忘了说 有个新的需求
你得给我弄一个
游戏初始化这样一个动作
程序必须过去留一个
调整游戏难度的接口”
这就是我们的需求分析
现在要做方案设计了
首先来做概要设计
响应需求A、E、F
将游戏分成四个模块
一个游戏的欢迎信息显示模块
一个游戏的初始化模块
一个游戏模块
还有一个游戏的结束模块
然后就可以设定整个程序的主框架
程序有“main.cpp”
还有程序主体的文件
“guess.h”和“guess.cpp”
另外还需要刚才使用到随机数库zyrandom
我们可以将每一个模块都抽取出来
形成单独的函数
有一个PrintWelcomeInfo
一个InitializeGane 一个PlayGame
还有一个PrintGameOverInfo
总共四个函数 前三个函数都没参数
返回值两个void 一个是double
最后一个函数
要带一个胜率的浮点数
返回值是个void
写到新的文件里
然后把文件命名为“guess.h”
这个头文件就算写完了
有了这个头文件
就可以写“main.cpp”了
主程序就包含这个头文件就行了
主函数里边
要做的就是这么几件事情
第一个要定义胜率的浮点数
然后打印欢迎信息
初始化这个游戏
然后开始玩这个游戏
结果就把它的胜率赋值到prevailed_ratio
这个变量里边
然后PrintGameOverInfo结束
这个就是“main.cpp”
就这道题来说“guess.h”、“main.cpp”
这两个文件其实就写完了
因为有了概要设计其实就已经决定了
程序的主体框架是什么
响应需求
比如讲这个游戏怎么玩
搞一个无限的循环 弄一个哨兵
一个回合结束就问用户“你还玩不玩”
他说“我不玩了” 退出游戏模块
这是一个基本的响应需求C的动作
响应具体需求细节 比如说B2
每一个回合物品的实际价格
是随机生成的
100到200之间
因为价格是随机生成的
那就意味着在生成第一个随机数值前
必须有一个初始化的动作
那么 初始化的动作在哪里做
理论上来讲 不应该把它放在PlayGame
玩游戏的模块里边做
你应该把它放在InitializeGame
初始化游戏的模块里
但是你发现一个非常重要的地方
是什么呢
实际上这个游戏要玩很多个回合
每一个回合都要对游戏
进行明确的初始化
每一个回合再弄一个
初始化回合的函数
把生成随机的物品价格的函数
放到InitializeBout函数里
返回值就是给你随机生成物品的
实际价格
这是一个好方案
接下来响应需求D
我要统计获胜的回合数
和全部的回合数
然后我好用它来算胜率
所以这个简单 定义两个量就完事了
玩游戏分成好多个回合
每一个游戏回合也把它抽象成函数
称它为PlayBout
再抽取出一个函数Again
我就问你 要不要再玩
Again这个函数的返回值就是bool量
这一点倒和PlayBout那个函数是一样的
为什么Again要返回bool量呢
这是要问用户还要不要继续玩
他说“我还要玩”那返回值就是true
如果“我不玩了” 返回值就是false
回到PlayBout
为什么返回值是bool量
游戏这一回合都做完了
猜对了返回true 否则返回false
这个就是标准的PlayBout和Again
接下来响应需求B1和B3
完成标准的数据初始化工作
就是它的最低价、最高价
他猜测的次数
我们把它定义成常量
放在我们的代码里