USB(universal serial bus,通用串行总线)提供了一个标准接口,可以将各种设备连接到计算机。同样的,接口在软件中也非常常见。设计良好的软件的特征就是接口和实现可以清晰的区分开来。接口是一组方法、函数以及这些方法和函数可用的数据类型的名称。正如硬件的USB接口一样,它展现给我们的只是一个扁长的物理接口,而一般不关心它内部的布线,电路板是怎样的,我们在外部访问计算机的资源时,只需要与计算机接口进行连接即可。同样的,我们在访问软件的资源时,也可以只与其接口相连接。这些资源如何实现的细节,也就是底层的算法代码和数据结构,都隐藏或封装在一个抽象的边界之中。这个边界将接口和实现隔开。
1. 开发接口
在python中,我们可以通过help函数来获取模块,数据类型或函数的相关信息,每次使用help都会访问有关资源接口的文档。比如我们help一个方法时,会看到一个方法头列表,包括方法的名字,参数的类型,及方法的返回值等。如下图所示:
接口就是简练而且丰富的、使我们只需看一下公开的、外在的“表面”,就能掌握资源的行为。接下来为包的简单的集合类型开发接口。包接口允许user高效的使用包,并允许实现者生成实现了该接口的新的类。
1.1 定义包接口
一个资源的接口中的方法表达了资源的行为,它所做事情的类别或者我们可以对它所做的事情。首先我们需要为包接口能做的操作定义一些函数名、方法名。比如我想在包操作中做len操作,即包集合的长度;我想判断包集合是否为空,那么我需要定义一个名为isEmpty的函数等等。
就像上图中一样,我们执行help(np.array)操作时,帮助文档里面有函数说明,即np.array是干什么的,以及参数和返回值(返回值没有截图截进去)。那么我们对包接口优化就是需要为接口中的操作添加参数,并考虑他们返回什么值。
我们称len、isEmpty为访问方法,同时,包接口类还需要定义一个构造方法,在python中,构造方法由__init__()实现。
满足了以上的要求后,接下来我们使用Python来编写一个接口框架。
有了接口框架,接下来我们分别基于数组和链表对接口进行实现。
2. 基于数组的实现
包接口类的设计和实现包含两个步骤:
1. 选择一个合适的数据结构来包含集合的项,并且确定可能需要表示集合状态的任何其他数据。将这些数据赋值给__init__方法中的实例变量
2. 完成接口中指定方法的代码
具体的代码实现如下:
3. 基于链表的实现
在链表的实现中,同样需要完成包接口中定义的那些方法的代码编写,那么我们可以直接将数组实现中的方法直接copy到链表实现的代码中,那么我们该copy哪些方法呢,是全盘copy还是只copy具有某些性质的方法;在上面数组实现的代码中我们可以看到,__isEmpty__、__len__、__add__、__eq__和__str__方法都没有直接访问数组变量,因此这些方法也不需要访问链表变量,那么我们就可以把这些方法直接copy到链表实现的模块中。接下来,我们只需要更改__init__、__iter__、clear、add和remove方法即可。具体的代码实现如下:
4. 测试包的实现
可以看到在数组实现和链表实现的代码的最后都进行了包实现的测试,但是每次实现都在最后加这么多的代码,这样复用性不高,所以我们可以专门定义一个测试函数,这样测试的时候只需把包作为参数传入到测试函数,具体代码实现如下:
此测试代码中的测试的内容和上面第二三节中的测试的内容不太相同。