1.4 拥抱变化
?需求简述
大部分初学者在编写双向链表时,为了验证相关函数是否能正常工作,都会去编写一个dlist_print函数,它的功能
是在屏幕上打印出整个双向链表中的数据。客观地说,用dlist_print输出的信息来判断dlist的正确性并不是最好的办
法,不过有保障程序质量的意识总是值得表扬的。当把专用双向链表演化成通用双向链表时,编写一个dlist_print就不
那么简单了。这里请大家自行写一个dlist_printf函数,看看会遇到什么问题。
在专用双向链表中,dlist_printf的实现非常简单,如果里面存放的是整数,用 %d 打印,存放的是字符串,用 %s
打印。现在的麻烦在于双向链表是通用的,我们无法预知其中存在的数据类型,也就是说我们要面对数据类型的变化。
怎么办呢?初学者可以参考的常用方法有以下几种。
实现多个函数,需要哪个就用哪个
比如实现dlist_print_int用来打印存放整数的双向链表,dlist_print_string用来打印存放字符串的双向链表等,
其他类型都有自己的打印函数。
不过这种做法也有一些缺点。一是每个函数的实现方式类似,会带来大量重复的代码。二是由于数据类型的种类不
确定,如果为每种数据类型都实现一个print函数,当要存放新的数据类型时,就不得不修改dlist的实现。
传入一个附加参数来决定如何打印
比如传入1表示按整数方式打印,传入2表示按字符串方式打印,以此类推。
这种做法比第一种好一点,至少不会造成大量重复的代码。但是同样存在增加新类型时要修改dlist_print函数的问
题。
调用dlist的接口函数获取每一个位置的数据并打印出来
这种方法没有前面两种方法的缺点,而且是一种相当直观的方式。但奇怪的是偏偏很少有人使用这个方法,原因可
能有两个:其一是太拘泥于传统的实现方式而没有想到这一种;其二是担心性能问题,因为通过索引取值,每一次都要
从头开始定位,其性能开销为O(n*n)。
其实这种方法是可以接受的,dlist_print函数只是用于辅助测试,我们并不需要太在乎它的性能开销,而且我们很
少会在链表中存放成千上万的数据,因此这个函数带来的性能影响根本没有想的那样严重。
不过在这里我们要介绍一种新的方法。
dlist_print的大体框架如下。
DListNode* iter = thiz->first;
while(iter != NULL)
{
print(iter->data);
iter = iter->next;
}
在上面代码中,我们主要是不知道如何实现 print(iter->data); 这行代码。那么谁知道呢?很明显,调用者知道
,因为调用者知道链表里面所存放的数据类型。好吧,那就让调用者来做好了,调用者在调用dlist_print时会提供一个
函数给dlist_print来调用,这种回调调用者所提供函数的方法,我们可以称之为回调函数法。更多相关内容http://www.cnblogs.com/rqialisvbs/