面向对象程序先导课是体系化面向对象课程的重要组成部分,其目标是帮助那些有一定C语言基础,但对面向对象概念陌生,基本没碰过Java编程的同学。该课程设计为暑期选修课,因为没有其他课程,我们设计为现场训练性质的训练营课程,即课堂上基本上不会通过ppt来讲授Java语言语法和面向对象知识点,而是围绕准备好的任务,课堂现场让大家进行程序联系,并结合所练习的程序现场讲解涉及到的Java语言和面向对象概念,这是一种面向问题和学生接受情况的教学模式。
整个课程包括四次,一次四个小时,分别安排在周二和周五。每次课程不以自然的45分钟为节点,而是按照训练任务为节点,效果非常好。看到的是同学们全情投入,偶尔有同学起身去趟厕所。
第一次课
目标:从C语言编程思维带入初步的面向对象编程思维。要点是认识面向对象程序的基础特征,以及它的妙处。
首先使用30分钟介绍课程目标以及概要性的Java语言介绍,即为什么会有这门课,以及通过两周训练达到150行有效Java程序的能力。我看到很多同学的眼睛里其实将信将疑。然后现场指导大家安装Java开发环境:JDK8 + Eclipse IDE。在安装之后,助教现场介绍IDE中的常用视图(Java Perspective, Debug Perspective)和操作,如新建项目,如何新建类,以及代码编写时的语法高亮和编译错误提示等。
亮点是下面这幅图:
要用差不多2个半小时来完成如图所示的6个任务。我们首先把样例代码发给同学们,然后一步步来完成任务1~任务6。初始程序具备完全的C风格,Box是个数据结构,main方法操作该数据结构,并进行volume计算。
任务1:为Box类添加volume方法计算容积。该任务向OO过度,让同学们了解到Java中的数据结构管理数据并提供数据计算方法。此外,通过该任务,同学们了解到如何编译和执行程序,特别是通过System提供的out来观察程序运行状况。
任务2:该任务训练通过方法返回值来达到不同类之间的“交互”目标。任务1的方法自成一体,完成计算和输出。任务2则不同,完成计算并返回计算结果,这体现出一定的职责划分,即Box类只负责计算自己的体积,如何与用户交互则是主类FirstJava的任务。
任务3:该任务帮助同学们进一步体验面向对象程序的不同,即可以有多个同名的方法(重载)。通过这种机制,一个类提供命名统一、功能相似但又有差异的方法。
任务4:未初始化数据是新手经常遇到的一个困难,导致程序运行中轻则出现错误,重则导致崩溃。面向对象程序提供了内在的初始化机制,即构造方法。该方法的特别之处在于与“数据结构”同名,这在C语言程序中也是做不到的事情。一旦添加了构造方法,同学们立刻注意到main方法中的new Box()语句报错,这是个好时机,来介绍Java默认的构造方法和显式定义构造方法的关系。
任务5:面向对象程序的一个重要机制是保护数据,这一点和C程序有本质区别。该任务介绍数据可见性概念,介绍三个重要关键词public, private和protected。一旦把Box的三个属性声明为private,立刻导致外面对这三个属性的访问出现语法错误,达到了数据保护的目标。至此,我们完成了一个内容完整的面向对象式Java程序,类之间有交互和职责划分,Box类隐藏自己的数据,并提供多种体积计算手段/服务。主类FirstJava创建和管理Box对象,并提供输出能力。
任务6:有了Box类的强大能力,我们提出希望在此基础上只做一点点工作就可以得到能力更强大的类ScaleBox,添加一个scale属性,表示Box类几何参数的尺度(即单位,如以厘米为单位,则米对应的scale为10,而毫米对应的尺度为0.1)。这种机制在C语言程序根本就不可能,这个任务介绍面向对象中的一个核心机制,继承的直观含义,如何通过该机制来得到ScaleBox。重点是要改写Box类的volume方法,即计算时纳入scale因素。至此,我们形成了三个类,其中Box和ScaleBox都和FirstJava类建立交互关系,而Box类和ScaleBox之间建立抽象层次关系。实际练习效果来看,同学们能够很好的理解并掌握任务1~任务5中强调的内容,任务6则有些懵懂。不过这也正常,事实上继承的语义还是比较复杂,训练营课程的目标不在于深入掌握,而是获得一种直观体验,特别是使用场景的体验。
通过这6个任务的完成,同学们的积极性被极大调动起来,体会到这门课授课方法的新颖性。特别突出的是,第一次课期间同学们一旦遇到语法错误问题,基本都是举手请求老师和助教协助。而从第二次课开始,这种现象基本就没了。我们在讨论过程中多次强调,如何阅读语法错误提示,以及如何自主上网找相关辅助信息。
在这6个任务铺垫下,我们最后流出半个小时来开始作业。首先给定一个完整的C语言程序,实现字符集合功能。在此基础上,提供一个框架性的Java代码,要求课堂实现相应的Java程序。这个任务基本没有太大难度,当然程序风格呈现出强烈的C特征。在此基础上,我们布置了作业的补充功能,即基于课堂所所完成的字符集合程序,使用继承手段,实现一个支持交集计算的字符集合,且能够记录集合提供服务的次数。