分享

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

 quasiceo 2014-01-05

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

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

    简介

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

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

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

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

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

方案一:最原始的方法

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

#if HELLO_MODULE
//hello.h
extern int api_say_hello(int times);

//hello.c
int 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_MODULE
extern 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_MODULE
extern 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.h
extern 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.c
int api_mock_fun()
{
   UNUSED_PARAM(arg1);
   return  NOT_SUPPORT;
}
//api_mock.c
int 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;
}
... ...

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多