程序设计是IT类专业工作者的看家本领,也是人们为解决复杂问题所需要的基本思维训练。但是在多年的教学实践和外出讲学调研中,笔者却发现,目前程序设计教学中普遍存在的三个突出问题:学习了程序设计课程,但碰到问题还是不知道如何下手;虽能编写程序,但用C++语言编写出来的程序却是面向过程的;编写出了程序却不知道如何测试。
1. 内容体系与写作思想
本书的写作目的就是试图从上述三个方面实现一些突破,改善C++的教学效果。全书分为3篇。第1篇共6个单元,第1单元介绍面向对象的基本概念;接着的4个单元各用一个实例帮助学习者快速进入面向对象世界,并掌握不同程序的基本测试方法;第6单元通过介绍面向对象程序设计的基本原则,使读者知晓如何设计出优美的面向对象的程序。第2篇用5个单元介绍C++支持面向对象程序设计的重要机制,使读者在学习了第1单元后,能在面向对象程序设计上上一个台阶。第3篇用4个单元使读者能进一步了解C++的一些细节。
采用这样的结构是出于如下几点考虑。
(1) 逻辑思维训练先行。
目前几乎所有的程序设计类教材都是采用面向语法的体系。这种从语言的语法手册改写而成的教材,尽管有人进行了“浅显易懂”的加工,说到底还是囿于应试,要把学习者的注意力引导到语法细节而不是程序设计的思路上,就会出现虽然学过程序设计,但遇到问题不知道如何下手的后果。
反思当前程序设计教材的这种弊病,本书第1篇采用了问题体系的写法,目的是把教材为中心的教学体系转移到以问题为中心的体系上来,加强基于算法的逻辑思维训练,通过一些经典的例子,介绍如何整理思路、构造解题算法,提高学习兴趣和解决实际问题的能力。
以问题为中心,加强基于算法的逻辑思维训练,不是不介绍语法,而是本着语法够用就行的思想,把语法和程序测试穿插于逻辑思维训练中。“皮之不存,毛将焉附”,不介绍语法,就不可能写出任何程序,进行逻辑思维训练成了一句空话。但是,语法够用就行,即只要能写出程序就行。
(2) 面向对象提前。
在经济学中有一个路径依赖(path dependence)理论:一旦人们做了某种选择,就好比走上了一条不归之路,惯性的力量会使这一选择不断自我强化,并让你不能轻易走出去。中国人将之称为“先入为主”。美国经济学家道格拉斯·诺思用这个理论成功地阐释了经济制度的演进规律,从而获得了1993年的诺贝尔经济学奖。在教学中,先入为主常常会使理论上认为简单、自然的方法更不易被接受,因为它要人们付出一定的转移成本。
现在的C++程序设计教材,尽管许多教材名上冠以“面向对象”,但却几乎都是从面向过程入手,讲词法、讲语法,然后转向面向对象。先入为主的训练,使得学习者无法理解书本中标榜的“面向对象是一种很自然的方法”。针对这种弊病,本书一开始就进入了面向对象的世界,对读者进行定义类-生成对象-操作对象面向对象的三步解题训练,并将面向过程作为面向对象的实现环节,将选择、迭代和穷举三种基本算法融入其中,避免思维模式转换带来的转移成本。
(3) 用设计模式点化面向对象。
不知道设计模式,就无法真正了解面向对象程序设计的精髓;不掌握设计模式中透射出的原则,就设计不出来优雅的面向对象程序。本书在通过前5个单元进行的基本算法和构建面向对象程序的基本过程训练之后,立即转入设计模式的学习。但是,设计模式对于许多人还是一条鸿沟。为了帮助读者越过这条鸿沟,本书采用了讲故事的方式,先引入从设计模式折射出来的几个面向对象程序设计的基本原则,然后对GoF设计模式进行概要介绍。
(4) 将程序测试融入程序设计之中。
程序测试的目的是找出程序逻辑错误,应该说是程序设计最后的重要环节。但是,这个环节却被人们忽视了。在程序设计课程的进行中,几乎所有学习者都是编写出一个程序后,只能靠碰运气地上机试通,等到学习软件工程课程(可惜并非所有学习程序设计的人都有再学习软件工程的安排),这种陋习已经难于纠正。而实际上计算机专业在上软件工程课程时,并没有很多时间用于程序测试的训练,就连软件工程专业开设的软件测试课程,也缺少充分的实践环节。从根本上讲,程序测试应当是程序设计不可或缺的组成部分,把程序测试的训练纳入到程序设计中,应该说是最高效、最合理的安排。基于如此考虑,从20世纪90年代初,作者就开始尝试将程序测试融入程序设计的教学中。实践证明,这不仅可行,而且很有好处。
(5) 淡化指针,分散安排。
指针是C和C++中最富有特色的机制,它把C/C++灵活、高效的特点表现得淋漓尽致。然而,指针又是程序中最容易出错、难以理解的部分。从20世纪80年代,就有人把指针与goto语句列入应当限制使用的“黑名单”。目前,一些新的C族语言,如Java、C#(读作c sharp)都向用户隐蔽了指针。对于初学者来说,应当养成少用指针,尽量不用指针的编程习惯。为此没有专门介绍指针的部分,而是将指针内容分散在必须使用的部分。
2. 学习环境与使用方法
由J.Piaget、O.Kernberg、R.J.sternberg、D.Katz、Vogotsgy等创建的建构主义(constructivism)学习理论认为,知识不是通过教师传授得到,而是学习者在一定的情境,即社会文化背景下借助其他人(包括教师和学习伙伴)的帮助,利用必要的学习资料,通过意义建构的方式而获得的。在信息时代,人们获得知识的途径发生了根本性的变化,教师不再是单一的“传道、授业、解惑”者,帮助学习者构建一个良好的学习环境成为其一项重要职责。当然,这也是现代教材的责任。本书充分考虑了这些问题。
本书中除了正文外,在每一大节后面都安排了概念辨析、代码分析、开发实践和探索深究4种自测和训练实践环节,建立起一个全面的学习环境。
1) 概念辨析
概念辨析主要提供选择和判断两类自测题目,帮助学习者理解本节学习过的有关概念,把当前学习内容所反映的事物尽量和自己已经知道的事物相联系,并认真思考这种联系,通过“自我协商”与“相互协商”,形成新知识的同化与顺应。
2) 代码分析
代码阅读是程序设计者的基本能力之一。代码分析部分的主要题型是通过阅读程序找出错误或给出程序执行结果。
3) 探索思考
建构主义提倡,学习者要用探索法和发现法去建构知识的意义。学习者要在意义建构的过程中主动地搜集和分析有关的信息资料,对碰到的问题提出各种假设并努力加以验证。按照这一理论,本书还提供了一个探索思考栏目,以培养学习者获取知识的能力和不断探索的兴趣。
4) 开发实践
提高程序开发能力是本书的主要目标。本书在绝大多数大节后面都给出了相应的作业题目。但是,完成这些题目并非就是简单地写出其代码,而要将它看作是一个思维+语法+方法的工程训练。因此,要求每道题的作业都要以文档的形式提交。文档的内容包括:
(1) 问题分析与建模;
(2) 源代码设计;
(3) 测试用例设计;
(4) 程序运行结果分析;
(5) 编程心得(包括运行中出现的问题与解决方法、对于测试用例的分析、对于运行结果的分析等).
文档的排版也要遵照统一的格式。
3. 感谢与期待
从20世纪80年代末,本人就开始探索程序设计课程从语法体系到问题驱动的改革;到了20世纪90年代中期又在此基础上考虑让学生在学习程序设计的同时掌握程序测试技能;2003年开始考虑如何改变学习了C++而设计出的程序却是面向过程的状况。每个阶段的探索,都反映在自己不同时期的相关作品中。本书则是自我认识又一次深化的表达。
尽管有了近20年探索的积累,但笔者却越来越感觉到编写教材的责任和困难。要编写一本好的教材,不仅需要对本课程涉及内容有深刻了解,还要熟悉相关领域的知识,特别是要不断探讨贯穿其中的教学理念和教育思想。所以,越到后来,就越感到自己知识和能力的不足。可是作为一项历史性任务的研究又不愿意将之半途而废,只能硬着头皮写下去。每一次任务的完成,都得益于一些热心者的支持和帮助。在本书的写作过程中,参加了部分工作的有姚威博士、陶利民博士、张展为博士以及张秋菊、文明瑶、史林娟、李博、张有明等。在此谨向他们致以衷心谢意。
本书就要出版了。它的出版,是我在这项教学改革工作跨上的一个新的台阶。本人衷心希望得到有关专家和读者的批评和建议,也希望能多结交一些志同道合者,把这项教学改革推向更新的境界。
张基温2012年10月10日