lab5.2代码分析:
-
linktableInternal.h:linkTable结构体是链表,包含链表头、尾结点,一个int型存储链表中节点值之和,以及一个互斥变量mutex;文件还定义了链表结点结构体LinkTableNode,这里只声明了最基本的属性即指向下一个LinkTableNode的指针pNext。
-
linktable.h:由linkTable和LinkTableNode定义新结构体tLinkTableNode和tLinkTable,文件基于这两个新结构体定义了链表的一些基本操作,如:删除链表、添加结点、删除结点、查找结点、获取头、尾结点等。
Callback回调函数指的是在某个函数执行完毕后自动调用的另一个函数。通常,我们将这个另一个函数作为参数传递给第一个函数,并在第一个函数执行完毕后调用这个参数函数。回调函数不是实现该函数的软件模块直接调用,而是在特定的事件或条件发生时由另外的软件模块通过函数指针的方式调用,用于对该事件或条件进行响应,是一种下层软件模块调用上层软件模块的特殊方式。
Callback函数需要一个Call-in函数,如SearchLinkTableNode函数,其中有一个函数作为参数,这个作为参数的函数就是callback函数,如代码中Conditon函数。打开llinktable.h,可以看到SearchLinkTableNode的定义如下:
/*
* Search a LinkTableNode from LinkTable
* int Conditon(tLinkTableNode * pNode, void * args);
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void * args), void * args);
其中放在参数位置的函数Condition允许用户自定义,通过这个办法实现了用户自定义查询条件,以在链表中查询结点的功能,在linktable.c中通过如下代码做到这一点:
/*
* Search a LinkTableNode from LinkTable
* int Condition(tLinkTableNode * pNode, void * args);
*/
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable,
int Condition(tLinkTableNode * pNode, void * args),
void * args)
{
if(pLinkTable == NULL || Condition == NULL)
{
return NULL;
}
tLinkTableNode * pNode = pLinkTable->pHead;
while(pNode != NULL)
{
if(Condition(pNode, args) == SUCCESS)
{
return pNode;
}
pNode = pNode->pNext;
}
return NULL;
}
在menu.c中定义了查询条件如下:
int SearchCondition(tLinkTableNode * pLinkTableNode, void * args)
{
char * cmd = (char*) args;
tDataNode * pNode = (tDataNode *)pLinkTableNode;
if(strcmp(pNode->cmd, cmd) == 0)
{
return SUCCESS;
}
return FAILURE;
}
并在findCmd函数中用到了这个在链表中按照给定查询条件查询结点的功能:
/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
return (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void*)cmd);
}
FindCmd调用SearchCondition,把自己的参数传给后者,可以选择①不给SearchLinkTableNode及其接口Condition加参数,声明一个全局变量,随用随赋值;②增加参数,在FindCmd函数体里把cmd链表指针传给SearchLinkTableNode。
根据如下集中耦合定义,①属于公共耦合,两个函数通过公共可访问的变量协作;②属于标记耦合,虽然显式传递的不是基本数据类型而是指针,但耦合度也比公共耦合低。
公共耦合
- 当软件模块之间共享数据区或变量名的软件模块之间即是公共耦合,显然两个软件模块之间的接口定义不是通过显式的调用方式,而是隐式的共享了共享了数据区或变量名。
数据耦合
- 在软件模块之间仅通过显式的调用传递基本数据类型即为数据耦合。
标记耦合
- 在软件模块之间仅通过显式的调用传递复杂的数据结构(结构化数据)即为标记耦合,这时数据的结构成为调用双方软件模块隐含的规格约定,因此耦合度要比数据耦合高。但相比公共耦合没有经过显式的调用传递数据的方式耦合度要低。
程序运行结果如下图所示: