9PASCAL语言(三)木氏程序分析模型

一个小小的课程设计,其实就是一个验金石,谁爱好编程、谁擅长编程一目了然。动手能力强的同学,课程设计常常做的又快又好,而且能帮助很多其他的同学。而动手能力差一些但是学习欲望仍然很强的同学,虽然在编程过程中会遇到各种困难,但总会想方设法的解决,甚至请出编程达人同学手把手的教。无论过程如何,他们必定亲手输入其课程设计的每一行代码。但是总还有另外一些同学似乎对动手编程毫无兴趣,或者天生惧怕,每每课程设计,总是拷贝抄袭、请人代劳或者在别人上交的软盘上写下自己的名字。

木鸿飞曾经认为,所有的学生都能学好程序设计,怀着这样的想法,他教授了几批学生。但在这过程中发现,有人对程序天生友好,稍一点拨就醍醐灌顶,思如泉涌,甚至举一反三。他们从听闻项目名称开始,大脑就高速运转,如此这般,如此这般,思路清清楚楚,一目了然。待到输入代码时,更是十指齐飞,工作效率与普通人不可同日而语。

但还有人却似乎对程序天生迟钝,无论怎么教,怎么学,就是不知道怎么做。就如同牙膏般,挤一点出一点,更有甚者挤了半天也不出一点。即使这次完成了,下次稍有变化,又茫茫然不知所终,真是急煞人也。对此木鸿飞常常无奈的叹气,如果说他们笨吧,但做起其他事情来一个比一个聪明。如果说他们懒吧——是有一点——布置的程序设计常常不能完成,但问题是这些同学独立设计程序的能力很差,绞尽脑汁也不知道如何下手,只能空坐在电脑前发呆,即便编码也会错误连连。老师不能总守着,也没有其他同学可以咨询,久而久之“远编程而近游戏”就成为了习惯。

究竟是什么原因造成了这个现象,这在教育界没有定论,但木鸿飞在不断的摸索与实践中,却略有心得。

成功开发软件的内在要素,无外乎分析、语法、系统、设计和工具。先说工具,很多课程设计本身很简单,并不需要复杂的三方控件或特殊专业知识,而集成开发环境的操作方法也并不复杂,新建、编译、运行等等按钮简简单单明明白白,所以工具不是原因。

再看设计,是否因为编程技巧不高而导致无从下手。不可否认部分同学由于很少动手,编程技巧急待提高,但技巧不足常常是代码行冗长和错误连连的罪魁祸首,还不足以导致编程时头脑一片空白、毫无头绪。

同理,一般课程设计很少使用操作系统的特性,同时大家对语法的掌握程度毋庸置疑。所以种种迹象表明,造成程序生疏的直接原因就是分析,即学习者严重缺乏系统分析、数据建模等方面的能力。

本处纠正一个观点,部分人认为系统分析是系统分析师的工作,是项目组长的责任,项目组普通成员或者小项目无需系统分析。这是不正确的,在设计任何一个程序之前都需要分析,大系统有大系统的分析,小程序有小程序的分析。即便设计从1连续加到100这样的简单程序,也必须先分析后编程,只是过程过于简单,在头脑中一闪而过,刹那间完成,感觉不到罢了。

当缺乏分析能力,无法正确进行分析和建模时,不同的人常常有不同的表现。有的人喜欢“知之为知之,不知为不知”,每每谈论程序,他们都沉默是金,三缄其口,实在躲不过,就会蹦出三个字:“不知道。”

(某计算机课堂上)

木老师:同学们,你们都用过TT打字练习程序吗?

众同学(稀稀拉拉):用过。

木老师:想不想自己设计TT程序?

众同学(异口同声):想。

木老师:本次课程设计就是设计TT软件。

众同学(摩拳擦掌):好!

木老师:那么现在请大家先思索几分钟,TT程序应该如何设计,也就是平时我常教的,应该如何建模?(教室里平静了三分钟),不知名的同学甲,你来回答。

不知名的同学甲:(起来,然后沉默)

木老师:不要紧张,你会如何设计TT程序,想到什么就说什么。

不知名的同学甲(仍然沉默,然后很轻声):不知道。

木老师:设计TT程序,首选什么数据结构。

不知名的同学甲:不知道。

木老师:TT程序会涉及了那些操作,比如计算时间之类的,想想还有什么?

不知名的同学甲:不知道。

木老师:假设TT程序已经编好了,用户会怎么使用。

不知名的同学甲:不知道。

木老师:你贵姓。

不知名的同学甲:不知道。

木老师:不是吧,貌似你刚刚最兴奋,不要紧,勇敢的讲出你心中的想法,错了也没关系。

不知名的同学甲:我睡着了,被他们吵醒了,不知道是什么事情,跟着叫唤的。

……

还有另一些人却正好相反,面对程序设计,无论是否首次接触,他们貌似总有自己的见解,建模方案和设计手段层出不穷,思如泉涌、口若悬河甚至手舞足蹈,仿佛胸有成竹熟悉无比。但一旦要真正编程时,嘴巴不灵了,手脚不便了,思路枯竭了,就像换了一个人似的。

(大学宿舍中)

帅哥张:今天编译原理老师布置了课程设计,做一个词法编译器LEX,你们有思路吗?

教授(面带愁容):毫无头绪。

柳轻侯:这个真的很难,我还要考虑一下。

木鸿飞:我也是略懂,正在深入体会中。

于谦(满不在乎):谁编好后记得给我挂名,我请他吃KFC

牛人生(洋洋得意):词法编译器,很容易啊!其实它就是把输入的一段文字区分为不同的单词而已。

木鸿飞:是啊,但是到底如何区分呢?

牛人生:很容易啊,它分为两个部分,一个部分记载所有的单词,当然是以正则表达式的方式记载的。另一个部分则分析文字,以有线自动机的方式将文字分解为一个个的单词,……

木鸿飞:嗯,讲的不错,要不我们合作开发吧。

牛人生:严重同意!你负责编程序,我负责提供思路和设计方法。

木鸿飞:还是一起编程吧,一个人写程序速度太慢。

牛人生:思路很重要,想好了思路,事半功倍。如果没有思路,程序是编不下去的。

木鸿飞:这样不好吧,要不,你设计第一部分,我设计第二部分。

牛人生:别咯!你编程序,有什么不懂的地方来问我就行了,我有的是办法。

……

其实,系统分析人人都会,之所以度不同而已。度太浅就是夸夸其谈,无法形成可行的方案。度太深则缺乏全局观念,容易陷入一个个细节当中无法自拔。那么如何才能掌握这个度呢?就请欣赏下面的实例,希望大家能有所感悟。

实例:分析TT打字练习程序

分析1:沙发。

分析2:好东西,可以围观。

分析3:太好了,我要学习。

分析4:不知道。

评论:此处忽略以上毫无营养的分析。

分析5:在上面显示一行文字,在下面等待输入,错误的就以红色标记,最后显示分数。

评论:这是典型的需求,程序设计前的必修课,外行和夸夸其谈者常止步于此。

分析6:用一数组存储显示出来的用以提示用户输入的文字,称之为提示数组。用另一个数组存储用户实际输入的文字,称之为打字数组。如果两数组对应位置的元素相同则说明用户输入正确,反之就是输入错误,正确的总数除以数组长度就是正确率。

评论:此乃建模,系统分析关键之所在。正所谓外行看热闹,内行看门道,对于计算机软件设计而言,门道就是模型,就是掩藏在缤纷复杂的表象下的数据结构和算法。只有真正提出了数据结构和算法,才可能实现程序,才不会坐在电脑前毫无头绪,否则就是夸夸其谈。分析5是必须的,但仅有分析5是不够的,因为分析5中没有可供实施的具体方案,所以分析6实现了由外行到内行的飞跃。

分析7:提示数组中的元素,可以用随机数的方式生成。具体生成算法容以后详细考虑。

评论:列举程序可能需要的算法,并点明实现该算法的关键,无需马上指出具体实现。

程序具备某项功能,则必定会有相应的算法支持,有的算法比较简单,可以一带而过,有的算法则比较复杂,需要仔细思考。比如扫雷游戏必定有埋雷算法,连连看游戏必须有匹配算法。算法常常不止一个,比如俄罗斯方块游戏中,至少有方块移动算法、方块旋转算法和方块消除算法等多个。

分析7有三个优点:其一、列举了必要的算法;其二、点明了实现该算法的核心,本处为随机数;其三、拿得起放得下,抓主线略细节,并不在此深究算法,本处只需记录下程序所需要的每一个算法并假定已经实现,待所有主线思索清晰后再回过头来逐个突破。

分析8:生成算法有几种,比如随机生成025,写入数组时为a+随机数。也可以为所有可能出现的字符建立一个索引,随机生成0~最大字符数-1,写入数组值为该索引对应的字符。

评论:算法的具体设计,对分析7中列举出的所有算法一一设计,当然针对同一个功能也可以提供若干个算法,然后从中选取最适合的一种。

分析9:程序接收键盘输入,存入打字数组对应位置中,并在屏幕上回显字符。同时判断是否输入正确,倘若错误则在相应的位置输出红色的惊叹号。

评论:以上是对程序中行为的分析,行为一般是需求的细化,常常不止一个。比如在俄罗斯方块中,至少包含定时结束方块下落,接收并处理键盘关于左移、右移、旋转和加速下移的指令等多个行为。

行为在某种意义上是需求内容之一,故外行或者夸夸其谈者也会有本分析流出,但他们无法详尽每一个行为,并且无法提交针对该行为的可行性设计方案。

分析10:分析9中多次提及“对应的位置”,具体来讲包括当前要输入的是显示数组中的第几个元素,字符存入的打字数组中第几个元素,输入字符回显到屏幕的具体位置,惊叹号显示的具体位置等四个内容。理论上需要四个数据才能存储以上四个位置,但实际上这四个位置之间存在特殊的联系,它们与起始处的相对位置是相同的,所以可以定义一个整型l为当前字符的位置,假设显示数组为a,打字数组为b,首字符横坐标为x,那么对应的数组元素分别为a[l]b[l],而在屏幕回显和惊叹号的横坐标就是x+l

评价:对分析9中的行为进行再建模,这里体现了一种迭代的思想,在大范围建模后(两个数组)又在小范围建模(对应位置)。

能不能从复杂的表象中发现程序的本质,是成为真正的程序员的关键。默不作声者可能为表象所迷惑,而夸夸其谈者则只注重眼前,他们均未能更进一步,或者说他们心有余而力不足,不知道如何透过现象看本质。以本处为例,需要对比显示的字符与输入的字符是否一致,但显示的字符到底是何方神圣?夸夸其谈者只觉得该字符就在屏幕上,所以不会去思考。而默不作声者虽然隐约的感觉事情不是想象中的那么简单,但由于编程太少,无从下手。他们并不知道本处的核心就是确定这个字符在内存中的存储位置。倘若能够思考至此,那么神马迷雾都是浮云。

至此,对TT打字练习程序的系统分析大体完成了,此后就可以条理清晰地进入详细设计和编码阶段。

分析方法多种多样,本处借用打字练习程序,介绍独创的“木氏程序分析模型”,如下图所示:

木氏程序分析模型

木氏程序分析模型由建模(modeling)、算法(algorithm)和行为(action)三个对象组成,简称MAA模型,此三对象之间相互关联,每个对象又可细分成分析(analysis)和设计(design)两种内容。

建模就是确定程序的需求和实现框架。建模分析寻找程序的所有需求,报告针对用户的外部需求和针对设计者的内部需求。比如上文中对TT程序的描述(分析5

建模设计则分析程序的内部实现,核心是找出适合程序的数据结构和算法,其中尤以数据结构为最。因为数据结构是算法的核心与基础,正如经济基础决定上层建筑一般,数据结构决定算法,算法根据数据结构的改变而改变。比如上文中使用数组存储字符(分析6)。建模设计是程序由虚入实的关键。

算法分析阶段需要列举程序所涉及的所有算法,当然不能是简单的罗列,更为重要的是必须知晓实现该算法的核心思想。比如上文中标明生成字符串的核心思想是随机(分析7),又比如游戏中寻路径算法的核心是深度或广度优先搜索等等。如若不能标明核心思想,则算法必然是无的放矢、夸夸其谈,甚至根本不能实现。

算法设计则将上述的思想落到实处,提出彻底可行的流程。对于简单的算法可以在列举后同时设计流程,而对于复杂的算法,只要确定其可行性,为避免思路受阻、分析中断,可以暂且略过,待到主线分析完毕后再回头设计。

行为分析是更微观的建模分析,它可以是来自外设的行为,也可以是来自系统对象的行为。随着分析的深入,行为也会更加细致。

行为设计是以可行的方式设计行为,可以在总体模型的基础上对行为进行细节性再建模,以使原有模型更加完善。

当然,实际情况瞬息万变,复杂万分,在具体设计时模型内容会有稍许增加。比如设计某项大型项目,前期还会有复更杂的步骤,比如设计拓扑结构,划分对象模块等。因此在应用本模型时要注意以下几点:

第一,分析时必须遵守从主线到细节的原则。只有建立了主体模型,才可以思索算法,然后再是具体设计。千万别在神马都是浮云的时候就仔细设计具体实现。没有主线只有支流只会使你的思维更加混乱,到达无从下手的最高境界。

第二,操作时必须牢记当前步骤的工作范围,设计到大体的模型和算法即可,切不可继续细化到每一行代码。需知诸如设定几个变量,使用什么循环之类的东东是下一步的工作计划,若是提前出现除了带来扰乱思维、增加工作量等恶性后果之外,不会附加任何好处。

第三,整个分析过程不会一蹴而就,也会有一个反复迭代的过程。比如在分析过程中可以对原有模型进行修改完善。又比如从行为分析到行为设计本身就是一个再建模过程,在分析该行为时很可能形成一个新的模型。有时一个大项目会划分为很多小项目,这些小项目又会继续细化为更小的项目。在面向对象方法设计时,会将系统划分为若干对象。这些小项目或小对象均有可能是一个新的模型。

最后,必须声明的事,任何事情都有一个熟能生巧的过程,系统分析也不例外。大家是不是看了上面的分析实例忽然觉得热血沸腾,发觉原来程序分析是如此简单如此清晰的一件事情,产生一种天下程序尽在我手上的错觉,以为自己一下子就转职为编程高手。殊不知好事多磨,只有多做系统分析方面的练习,才可以真正的掌握以上方法的精髓,才可以笑傲程序。否则,你无法透过现象看到本质吗,无法快速并且正确的建模。

不经一番寒彻骨,哪得梅花扑鼻香。不经过一番刻苦的练习,即使背熟了模型,也是纸上谈兵,仍然无法直击本质,无法活用数据结构。恐怕一边摇头一边高唱“借我借我一双慧眼吧,让我把这程序看得清清楚楚明明白白真真切切”就是真实的写照。

倘若有心练习,有大量的实例可供选择。远的不说,就拿大家喜爱的游戏程序来说,从俄罗斯方块、贪吃蛇、扫雷,到连连看、祖玛,植物大战僵尸等等都可以成为练习的素材。甚至可以留意生活中一切可能接触到的应用程序,反向思索其系统分析,比如与朋友们一道卡拉OK时,就可研究点歌程序;使用了一个背单词软件,也可以分析其设计模型。不用担心练习太多,时间无多,分析毕竟是分析,不涉及编码,免去了很多烦人的细节,不会占用太多时间,所以多多益善。当然很有必要从中选取一二完全设计,如此以来即可验证系统分析正确性,又可练习编码等必要能力,还可以得到上台面的成果,实在是学习编程、树立名气、诱惑MM的必备良药。

上一篇   目录  下一篇