模块化编程-以图书管理系统为例
为了实现一个完整的业务功能,一般来说你的代码会包含至少三种类型的代码:
- 界面显示代码:用来显示界面、输出数据。
- 数据处理代码:一般来说只对数据进行处理。比如,对存在数组或链表中的数据进行增删改查。
- 交互类代码:处理用户的输入与输出。比如,根据用户输入调用"数据处理代码"处理数据,调用"界面显示代码"显示数据或显示界面,从而实现一个完整的业务功能。
比如,对于图书管理系统的功能“添加图书”,有的同学这样编写。
AddBook()
{
// 显示菜单的代码-类型1
// 提示用户输入、从控制台读入用户输入数据-类型3
// 根据输入进行数据处理的代码。比如在链表中添加某个节点-类型2
// 将输出输出或者显示菜单-类型3
// 为了编写方便可能还需大量地使用了全局变量。比如,为了往图书列表中添加数据,需访问全局变量booklist。
}
这样编写,固然易于实现,然而不符合模块化编程思想。代码中,数据处理代码、界面显示代码、交互类代码耦合,难以复用。
模块化编程
应将不同类型的代码封装到独立地函数中,方便复用。对于"添加图书"功能可以写如下几个函数:
- void AddBook(BookList booklist) //进入添加图书功能
- int AddBook(BookList booklist, Book book)//只包含在bookList中添加book的代码,不涉及任何界面与输入输出代码。返回状态码:-2,添加失败,因为已经存在;-1, 添加失败,因为分配内存不成功;其他正整数n,添加成功,返回值为添加的位置
说明:void AddBook(BookList booklist)使用一个booklist作为输入参数,就避免了使用全局变量。
图书管理系统伪代码
1. AddBook(BookList booklist)伪代码
AddBook(BookList booklist)
{
1. ListAllBooks(booklist); // 格式化显示所有图书的代码-界面显示代码
2. 处理用户需要添加的图书信息,生成了book结构体。 // 交互类代码
3. int status = AddBook(booklist, book); // 数据处理代码
4. 根据status进行相应的处理的代码,可能包含:// 交互类代码
- 提示添加出错,并显示出出错原因
- 提示添加成功与添加位置->DispBook(book)。注意DispBook为一个专门格式化显示Book的函数-界面显示代码。
5. 根据用户输入选择是继续添加还是返回。 //交互类代码
}
从这个例子中可以看到,交互类代码用来协调控制"数据处理代码"和"界面显示代码"。
在这里,交互类代码起到一个控制器的作用,处理输入->调用数据处理代码->根据执行结果选择合适的界面显示代码。
通过交互类代码的穿针引线,最终完成了"添加图书"这个完整功能。
2. main函数伪代码
main()
{
booklist = InitBookList() // 初始化图书列表。可能从文件系统读取图书数据,也可能直接通过代码生成数据。
while(true)
{
MainMenu() // 图书管理系统主菜单-界面显示代码。
choice = input(); // 提示用户输入选择-交互类代码
switch (choice) {
case 1: // 浏览图书列表
ListAllBooks(booklist);
break;
case 2: // 添加图书
AddBook(booklist)
break;
其他case...:
....
break;
default:
// 处理输入错误的情况
break;
}
}
}
这样的编写就比较符合模块化编程的思想:
- 每个函数只做一件事情。
- 有效地控制了函数的规模(行数)。
- 避免了对全局变量的使用。
- 方便了代码的复用。比如,这里通过ListAllBook、AddBook、DispBook、MainMenu这几个函数实现了代码复用。