5.9.1 模块化编程

5.9.1 模块化编程

从前面的案例中我们发现函数可以通过封装实现代码复用。函数是程序的一种抽象,可以利用函数对程序进行模块化设计。

程序是由一系列代码组成的,如果代码是顺序的但无组织,不仅不利于阅读和理解,也很难进行升级和维护。因此,需要对代码进行抽象,形成易于理解的结构。

当代编程语言从代码层面采用函数和对象两种抽象方式,分别对应面向过程和面向对象编程思想。

函数是程序的一种基本抽象方式,它将一系列的代码组织起来,通过命名供其他程序使用。函数封装的直接好处是代码复用。具体表现在任何其他的代码只要使用函数名,输入参数即可调用函数,从而避免了相同功能代码在调用处的重复编写。

代码复用又产生另一种优势,当更新函数功能时,所有被调用处的功能都被更新。

面向过程是一种以过程描述为主要方法的编程方式,它要求程序员列出解决问题所需要的步骤,然后用函数将这些步骤一步一步实现,使用时依次建立并调用函数或编写语句即可。面向过程编程是一种基本且自然的程序设计方法,函数通过封装步骤或子功能实现代码复用,并简化程序设计难度。

面向对象是一种更为高级的抽象方式。对象是程序的一种高级抽象方式,它将程序代码组织为更高级别的类。对象包括对象特征的属性、代表对象操作或行为的方法。如汽车是一个类,将类实例化即对象,一辆红旗汽车是一个对象。车的颜色、车型、轮胎数量等是属性,代表汽车的静态值。汽车前进、后退、转变等是方法,代表汽车的行为和动作。

在程序设计中,如果<a>是对象,获取对象<a>的属性<b>用<a.b>的形式,调用对象<a>的方法<c>用<a.c()>的形式,如前面学字符串时,若字符串为<'abcd'>,调用它的大写方法用<'abcd'.upper()>。

对象是程序模拟解决计算问题的一个高级别抽象,它包括一组静态值(属性)和一组函数(方法)。从代码行数的角度来看,对象和函数都使用了一个容易理解的抽象逻辑,但对象可以凝聚更多代码。因此,面向对象编程更适合代码规模大的、交互逻辑更复杂的程序。

面向过程和面向对象只是编程方式不同,抽象级别不同,所有面向对象编程能实现的功能采用面向过程同样能实现。

当程序较长时,如百行以上,如果不划分模块,程序的可读性就会非常差。解决这一问题最好的方法就是将一个程序分隔成短小的程序段,每一段程序完成一个小的功能。无论是面向过程编程,还是面向对象编程,对程序合理划分功能模块并基于模块设计程序是一种常用的方法,称为“模块化程序设计”。

模块化程序设计是指通过函数或对象的封装功能将程序划分成主程序、子程序和子程序间关系的表达。模块化程序设计是使用函数和对象设计程序的思考方法,以功能块为基本单位,一般有两个基本要求。

①高内聚。尽可能合理划分功能块,功能块内部耦合紧密。

②低耦合。模块间尽可能简单,功能块之间耦合度低。

耦合是指两个实体相互依赖对方的一个量度,在程序设计结构中是指各模块之间相互关联的程序。

也就是在设计系统的各个功能模块时,尽可能使模块具有较大的独立性,使得每个模块都完成一个相对独立的特定子功能,并且和其他模块之间的关系很简单,以便能把不同场合下写成的程序模块组合成软件系统。

衡量模块独立性的定性标准是内聚(一个模块内各个元素彼此结合的紧密程度)和耦合(一个软件结构内不同模块之间互连程度的度量)。高内聚、低耦合的模块是设计时追求的目标。尽量降低系统各个部分之间的耦合度,是应用服务层设计中需要重点考虑的问题。

模块化编程可采用以下步骤进行:

①分析问题,明确需要解决的任务;

②对任务进行逐步分解和细化,分成若干个子任务,每个子任务只完成部分完整功能,并且可以通过函数来实现;

③确定模块(函数)之间的调用关系;

④优化模块之间的调用关系;

⑤在主函数中进行调用实现。

模块与模块之间可以相互调用。假定模块1、模块2的程序文件分别在同一个目录下,保存的文件名为<module1.py>、<module2.py>,则模块2调用模块1的形式有:

①import module1;

②from module1 import*。

例如,创建python文件a.py,并在文件中定义函数sum():

创建python文件b.py,并调用sum()函数: