打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
降低耦合(1)API函数设计方法讨论

降低耦合(1)API函数设计方法讨论

0 条评论 2011/11/22 13:03 478 次阅读

    简介

    降低模块间的耦合性有不少方法,主要以下几种:

* API直接调用;
* 函数指针,(e.g. callback)
* 消息通讯(e.g. 订阅机制)
* 插件机制
* ...

其中API直接调用方式,虽然耦合性还是很高,但是其简单易用,使用较为广泛,本文将主要讨论:

为降低模块间耦合性,API函数应如何设计。

NOTE: 我个人比较倾向使用模块化的函数指针,以后再谈。

方案一:最原始的方法

最朴实的函数,用头文件暴露出去,供调用者们调用。 例如:

#if HELLO_MODULE//hello.hextern int api_say_hello(int times);//hello.cint api_say_hello(int times){... ...    return SUCCESS;}//caller.c#include "hello.h"int nret = api_say_hello(3);
问题

hello既然是模块,最基本的要求是:可以开关的;此方案开启时当然没有问题,一旦关闭编译都过不了。

方案二:可开关

  • 要解决无法开启的问题,在调用时加入一个专门的宏(HELLO_MODULE)来判断 hello 模块是否开启,继而决定是否调用API。
    //caller.c#if HELLO_MODULE#include "hello.h"int nret = api_say_hello(3);#endif

问题

一旦API多起来,调用者的代码中将充斥太多的ifdef ... else ... endif, 代码可维护性很差。

方案三:Mock API

Mock是单元测试中常用方法,意思是:模仿、假造、山寨……。 如何山寨一个API呢?
示意代码还是以方案一为基础,只修改头文件即可:

//hello.h#define NOT_SUPPORT -1#if HELLO_MODULEextern int api_say_hello(int times);#else#define api_say_hello(arg) NOT_SUPPORT#endif

问题

如果没有定义HELLO_MODULE,将执行 else中的代码:

#define api_say_hello(arg) (-1)

此时传入的参数没有使用会产生warning,一般不碍事,但如果代码要求较高,Makefile中 加入了-Werror(for 0 warning)这就是一个不得不面对的问题了。

方案四:Mock API no warning

去除warning的思路是在Mock API声明中加入一些特别处理:

//hello.h#define   UNUSED_PARAM(x)   ((void)x)#define API_MOCK_FUN() NOT_SUPPORT#define API_MOCK_FUN1(ag1)         UNUSED_PARAM(ag1);	API_MOCK_FUN() 	... ...#if HELLO_MODULEextern int api_say_hello(int times);#else#define api_say_hello(arg) API_MOCK_FUN1(arg)#endif

问题

当调用方法为int nret = api_say_hello(3); 没有任何问题,但如果调用者这样使用:

if(api_say_hello(3) ==SUCCESS){  //... ...}
将会出错, 原因是:
宏展开后:if(((void)3);NOT_SUPPORT == SUCCESS)if括号内不能有分号。

方案五:Mock API使用函数替换宏

将 API_MOCK_FUN1 的实现用 函数表示,参数类型为(void *),使用宏转换后传入:

//api_mock.hextern int api_mock_fun(void);extern int api_mock_fun1(void* arg1);extern int api_mock_fun2(void * arg1, void * arg2)...#define API_MOCK_FUN() api_mock_fun()#define API_MOCK_FUN1(ag1) api_mock_fun1((void*)arg1)#define API_MOCK_FUN2(ag1, arg2) api_mock_fun2((void*)arg1, (void*)arg2)...//api_mock.cint api_mock_fun(){   UNUSED_PARAM(arg1);   return  NOT_SUPPORT;}//api_mock.cint api_mock_fun1(void * arg1){   UNUSED_PARAM(arg1);   return  NOT_SUPPORT;}int api_mock_fun2(void * arg1, void * arg2){   UNUSED_PARAM(arg1);UNUSED_PARAM(arg2);   return  NOT_SUPPORT;}... ...
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
【Jabberd2源码剖析系列 mio】
RTOS内功修炼记(八)— CMSIS RTOS API,内核通用API接口
test_virtualfun.cpp
关于函数与指针以及函数指针的一些个人理解
从 Windows 移植到 UNIX,第 1 部分: 移植 C/C++源代码
C语言中可变参数的用法
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服