作业3:深入理解Callback函数

回调函数是一种通过函数指针调用的函数,当该函数指针调用其所指向的函数时,就称这是回调函数。

回调函数通常不是由实现该函数的软件模块直接调用,而是在特定的事件或条件发生时由另外的软件模块通过函数指针的方式调用,用于对该事件或条件进行响应。

在之前写的menu程序的基础上,我们为Linktable增加Callback方式的接口。该接口只需描述当前函数的功能,而不涉及具体的实现细节,实现该接口的代码被称为实现。通过将接口和实现分离,符合面向对象中多态的编程思想,系统的可以通过不同的实现丰富接口的功能。

基于lab5.2的代码分析。给Linktable增加Callback方式的接口,需要两个函数接口,一个是call-in方式函数,如SearchLinkTableNode函数,其中有一个函数作为参数,这个作为参数的函数就是callback函数,如代码中Conditon函数。
在linktable.c文件中的SearchLinkTableNode()函数,该函数的参数列表中有一个参数是函数,这个作为参数的函数就是callback函数

/*
 * Search a LinkTableNode from LinkTable
 * int Condition(tLinkTableNode * pNode, void * args);
 */
tLinkTableNode *SearchLinkTableNode(tLinkTable *pLinkTable, int Condition(tLinkTableNode *pNode, void *args)

call-in方式的函数接口SearchLinkTableNode()增加了一个参数args,callback函数Conditon也增加了一个参数args。为了追求松散耦合,我们增加一个args参数,代替共享cmd这一方式,降低耦合度。之所以要转成void类型,就是为了更通用,是因为我们不想让底层的linktable模块知道上层用的数据类型。这样同时也不影响找节点的功能。

在menu.c文件中的FindCmd()函数调用了上述SearchLinkTableNode()函数,如下

/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
    return  (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void*)cmd);
}

该函数调用传入了具体实现的SearchCondition()函数作为回调函数,并通过cmd参数传递命令名称。
SearchLinkTableNode()函数实现如下,在该函数中根据传入的命令参数及搜索条件回调函数进行命令节点的查找,并在函数体内调用了回调函数Condition()。

/*
 * 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;
}

该函数的返回类型为tLinkTableNode * 类型,而FindCmd()函数调用时把返回值强制类型转换成了tDataNode *类型。

在本实验中,使用回调函数作为参数增强了Linktable查询接口的通用性,有效地提升了接口的可重用性,这就是软件开发中解耦思想的体现。
menu.c文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linktable.h"

int Help();
int Quit();

#define CMD_MAX_LEN 128
#define DESC_LEN    1024
#define CMD_NUM     10


/* data struct and its operations */

typedef struct DataNode
{
    tLinkTableNode head;
    char*   cmd;
    char*   desc;
    int     (*handler)();
} tDataNode;


int SearchCondition(tLinkTableNode * pLinkTableNode, void * args)
{
    char * cmd = (char*) args;
    tDataNode * pNode = (tDataNode *)pLinkTableNode;
    if(strcmp(pNode->cmd, cmd) == 0)
    {
        return  SUCCESS;  
    }
    return FAILURE;	       
}

/* find a cmd in the linklist and return the datanode pointer */
tDataNode* FindCmd(tLinkTable * head, char * cmd)
{
    return  (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void*)cmd);
}

/* show all cmd in listlist */
int ShowAllCmd(tLinkTable * head)
{
    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
    while(pNode != NULL)
    {
        printf("%s - %s\n", pNode->cmd, pNode->desc);
        pNode = (tDataNode*)GetNextLinkTableNode(head, (tLinkTableNode *)pNode);
    }
    return 0;
}

int InitMenuData(tLinkTable ** ppLinktable)
{
    *ppLinktable = CreateLinkTable();
    tDataNode* pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "help";
    pNode->desc = "Menu List:";
    pNode->handler = Help;
    AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "version";
    pNode->desc = "Menu Program V1.0";
    pNode->handler = NULL; 
    AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "quit";
    pNode->desc = "Quit from Menu Program V1.0";
    pNode->handler = Quit; 
    AddLinkTableNode(*ppLinktable, (tLinkTableNode *)pNode);
 
    return 0; 
}

/* menu program */

tLinkTable * head = NULL;

int main()
{
    InitMenuData(&head); 
   /* cmd line begins */
    while(1)
    {
        char cmd[CMD_MAX_LEN];
        printf("Input a cmd number > ");
        scanf("%s", cmd);
        tDataNode *p = FindCmd(head, cmd);
        if( p == NULL)
        {
            printf("This is a wrong cmd!\n ");
            continue;
        }
        printf("%s - %s\n", p->cmd, p->desc); 
        if(p->handler != NULL) 
        { 
            p->handler();
        }
   
    }
}

int Help()
{
    ShowAllCmd(head);
    return 0; 
}

int Quit()
{
    exit(0);
}

linktable.c文件

#include "linktable.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Create a LinkTable
 */
tLinkTable *CreateLinkTable() {
    tLinkTable *pLinkTable = (tLinkTable *)malloc(sizeof(tLinkTable));
    if (pLinkTable == NULL) {
        return NULL;
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = 0;
    pthread_mutex_init(&(pLinkTable->mutex), NULL);
    return pLinkTable;
}

/*
 * Delete a LinkTable
 */
int DeleteLinkTable(tLinkTable *pLinkTable) {
    if (pLinkTable == NULL) {
        return FAILURE;
    }
    while (pLinkTable->pHead != NULL) {
        tLinkTableNode *p = pLinkTable->pHead;
        pthread_mutex_lock(&(pLinkTable->mutex));
        pLinkTable->pHead = pLinkTable->pHead->pNext;
        pLinkTable->SumOfNode -= 1;
        pthread_mutex_unlock(&(pLinkTable->mutex));
        free(p);
    }
    pLinkTable->pHead = NULL;
    pLinkTable->pTail = NULL;
    pLinkTable->SumOfNode = 0;
    pthread_mutex_destroy(&(pLinkTable->mutex));
    free(pLinkTable);
    return SUCCESS;
}

/*
 * Add a LinkTableNode to LinkTable
 */
int AddLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode *pNode) {
    if (pLinkTable == NULL || pNode == NULL) {
        return FAILURE;
    }
    pNode->pNext = NULL;
    pthread_mutex_lock(&(pLinkTable->mutex));
    if (pLinkTable->pHead == NULL) {
        pLinkTable->pHead = pNode;
    }
    if (pLinkTable->pTail == NULL) {
        pLinkTable->pTail = pNode;
    } else {
        pLinkTable->pTail->pNext = pNode;
        pLinkTable->pTail = pNode;
    }
    pLinkTable->SumOfNode += 1;
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return SUCCESS;
}

/*
 * Delete a LinkTableNode from LinkTable
 */
int DelLinkTableNode(tLinkTable *pLinkTable, tLinkTableNode *pNode) {
    if (pLinkTable == NULL || pNode == NULL) {
        return FAILURE;
    }
    pthread_mutex_lock(&(pLinkTable->mutex));
    if (pLinkTable->pHead == pNode) {
        pLinkTable->pHead = pLinkTable->pHead->pNext;
        pLinkTable->SumOfNode -= 1;
        if (pLinkTable->SumOfNode == 0) {
            pLinkTable->pTail = NULL;
        }
        pthread_mutex_unlock(&(pLinkTable->mutex));
        return SUCCESS;
    }
    tLinkTableNode *pTempNode = pLinkTable->pHead;
    while (pTempNode != NULL) {
        if (pTempNode->pNext == pNode) {
            pTempNode->pNext = pTempNode->pNext->pNext;
            pLinkTable->SumOfNode -= 1;
            if (pLinkTable->SumOfNode == 0) {
                pLinkTable->pTail = NULL;
            }
            pthread_mutex_unlock(&(pLinkTable->mutex));
            return SUCCESS;
        }
        pTempNode = pTempNode->pNext;
    }
    pthread_mutex_unlock(&(pLinkTable->mutex));
    return FAILURE;
}

/*
 * 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;
}

/*
 * get LinkTableHead
 */
tLinkTableNode *GetLinkTableHead(tLinkTable *pLinkTable) {
    if (pLinkTable == NULL) {
        return NULL;
    }
    return pLinkTable->pHead;
}

/*
 * get next LinkTableNode
 */
tLinkTableNode *GetNextLinkTableNode(tLinkTable *pLinkTable,
                                     tLinkTableNode *pNode) {
    if (pLinkTable == NULL || pNode == NULL) {
        return NULL;
    }
    tLinkTableNode *pTempNode = pLinkTable->pHead;
    while (pTempNode != NULL) {
        if (pTempNode == pNode) {
            return pTempNode->pNext;
        }
        pTempNode = pTempNode->pNext;
    }
    return NULL;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值