API设计 [英] API design

查看:81
本文介绍了API设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个库(通过

串口与多个设备通信)并对设计有一些疑问。我现在有一个

标题和源文件,如下所示:


/ * device.h * /

typedef struct device device ;


int device_open(device ** dev,const char * name);

int device_close(device * dev);

int device_read(device * dev,void * data,unsigned int size);

int device_write(device * dev,const void * data,unsigned int size);


/ * device.c * /


struct device {

/ *这里的一些数据* /

} ;


int

device_open(device ** dev,const char * name)

{

if(dev == NULL)

返回-1;


struct device * out = malloc(sizeof(struct device));

if(out == NULL)

返回-1;


/ *在这里做一些事情* /

* dev = out;

返回0;

}


如你所见,我做了内部数据结构通过

typedef和pointe不透明rs到不完整的数据结构。现在我的

问题是:


1.将typedef更改为


typedef struct是否有任何优势设备*设备;


因此隐藏了设备的事实。类型实际上是一个指针。


2.我想添加对第二种类型设备的支持,这恰好与第一种类型非常相似。例如,读/写函数

是不同的,但是开/关函数和

结构本身的内容是相同的。如何在不将

代码复制到一对新的头文件和源文件的情况下实现这一点?


我想将共享代码移动到一个共同的标题和来源

文件并使特定于设备的函数调用常用函数。

但我应该如何处理下面的typdef,因为两个结构都会
在我的情况下,
是相同的。但是我想向图书馆的用户隐藏




/ * common.h(仅供内部使用)* /


struct device {

/ *这里的一些数据* /

};


int device_open(device ** dev,const char * name);


/ * device1.h(public)* /

typedef struct device1 device1;

int device1_open(device1 ** dev,const char * name);

....


/ * device2.h( public)* /

typedef struct device2 device2;

int device1_open(device1 ** dev,const char * name);

... 。

I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a
header and source file like this:

/* device.h */
typedef struct device device;

int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);

/* device.c */

struct device {
/* some data here */
};

int
device_open (device **dev, const char *name)
{
if (dev == NULL)
return -1;

struct device *out = malloc (sizeof (struct device));
if (out == NULL)
return -1;

/* Do some stuff here */

*dev = out;
return 0;
}

As you can see, I made the internal data structure opaque by means of
the typedef and pointers to an incomplete data structure. Now my
questions are:

1. Is there any advantage to change the typedef to

typedef struct device *device;

and thus hiding the fact that the "device" type is actually a pointer.

2. I want to add support for a second type of device, which happens to
be very similar to the first one. For instance the read/write functions
are different, but the open/close functions and the contents of the
struct itself are the same. How can I implement this without copying the
code to a new pair of header and source files?

I was thinking to move the shared code to a common header and source
file and make the device-specific functions call the common functions.
But what should I do with the typdefs below, because both structs would
be the same in my case. But I would like to hide that from the user of
the library.

/* common.h (for internal use only) */

struct device {
/* some data here */
};

int device_open (device **dev, const char *name);

/* device1.h (public) */
typedef struct device1 device1;
int device1_open (device1 **dev, const char *name);
....

/* device2.h (public) */
typedef struct device2 device2;
int device1_open (device1 **dev, const char *name);
....

推荐答案



" Jef Driesen" < je ******** @ hotmail.com.invalidwrote in message

"Jef Driesen" <je********@hotmail.com.invalidwrote in message

我正在写一个库(与多个设备通信)在一个

串口上)并对设计有一些疑问。我现在有一个

标题和源文件,如下所示:


/ * device.h * /

typedef struct device device ;


int device_open(device ** dev,const char * name);

int device_close(device * dev);

int device_read(device * dev,void * data,unsigned int size);

int device_write(device * dev,const void * data,unsigned int size);
I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a
header and source file like this:

/* device.h */
typedef struct device device;

int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);



从标准库中取出一本书。


FILE * fp = fopen(" filename.txt"," w");

如果(!fp)

/ *它失败了* /

fprintf(fp," This file works\\\
");

fclose(fp);


类似


typedef struct device DEVICE;


DEVICE * dev = device_open(" Fred");

if(!dev)

/ *你的设备没有打开* /

device_write(dev,我的名字是弗雷德,15);

device_close(dev);


-

免费游戏和编程好东西。
http:// www。 personal.leeds.ac.uk/~bgy1mm

Take a book out of the standard library.

FILE *fp = fopen("filename.txt", "w");
if(!fp)
/* it failed */
fprintf(fp, "This file works\n");
fclose(fp);

Similarly

typedef struct device DEVICE;

DEVICE *dev = device_open("Fred");
if(!dev)
/* your device didn''t open */
device_write(dev, "my name is Fred", 15);
device_close(dev);

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm




" Jef Driesen" < je ******** @ hotmail.com.invalidwrote in message

news:wo ******************** *** @ phobos.telenet-ops.be ...

"Jef Driesen" <je********@hotmail.com.invalidwrote in message
news:wo***********************@phobos.telenet-ops.be...

我正在写一个库(通过

串口)并对设计有一些疑问。我现在有一个标题

和这样的源文件:


/ * device.h * /

typedef struct device device ;


int device_open(device ** dev,const char * name);

int device_close(device * dev);

int device_read(device * dev,void * data,unsigned int size);

int device_write(device * dev,const void * data,unsigned int size);
I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a header
and source file like this:

/* device.h */
typedef struct device device;

int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);



device_open很难看,IMO:

device * device_open(const char * name);

会有点不那么难看。

device_open is ugly, IMO:
device *device_open (const char *name);
would be a little less ugly.


/ * device.c * /


struct device {

/ * some这里的数据* /

};


int

device_open(device ** dev,const char * name)

{

if(dev == NULL)

返回-1;


struct device * out = malloc(sizeof(struct device));

if(out == NULL)

返回-1;


/ *在这里做一些事情* /


* dev = out;

返回0;

}


如您所见,我通过

typedef和指向不完整数据结构的指针使内部数据结构不透明。现在我的问题

是:


1.将typedef更改为


typedef struct是否有任何优势设备*设备;


因此隐藏了设备的事实。 type实际上是一个指针。
/* device.c */

struct device {
/* some data here */
};

int
device_open (device **dev, const char *name)
{
if (dev == NULL)
return -1;

struct device *out = malloc (sizeof (struct device));
if (out == NULL)
return -1;

/* Do some stuff here */

*dev = out;
return 0;
}

As you can see, I made the internal data structure opaque by means of the
typedef and pointers to an incomplete data structure. Now my questions
are:

1. Is there any advantage to change the typedef to

typedef struct device *device;

and thus hiding the fact that the "device" type is actually a pointer.



这可能是可以接受的(我实际上在一个

点处使用void指针类似):

typedef void * dyt;


其中dyt隐藏它是一个指针。

这是个人偏好。


在我的情况下,''dyt''是一个动态类型的特定''动态类型''API

我...

this may be acceptable (I actually do similar with a void pointer at one
point):
typedef void *dyt;

where dyt hides that it is a pointer.
this is a personal preference though.

in my case, ''dyt'' is a dynamic type for a specific ''dynamic type'' API of
mine...


2.我想添加对第二种类型设备的支持,恰好与第一种设备非常类似。例如,读/写函数是不同的,但是开/关函数和结构的内容

本身是相同的。如何在不将代码复制到

a新的头文件和源文件的情况下实现这一点?
2. I want to add support for a second type of device, which happens to be
very similar to the first one. For instance the read/write functions are
different, but the open/close functions and the contents of the struct
itself are the same. How can I implement this without copying the code to
a new pair of header and source files?



a典型方法是利用结构填充函数指针。

这些存在于每个类型,并由特定的打开实例引用。


struct device_info_s {

int(* close)(device * dev);

int(* read)(device * dev,void * data,unsigned int size);

int(*写)(device * dev,const void * data,unsigned int size);

};


前端函数然后通过这个结构调度。 />

int device_close(device * dev)

{

if(dev-> info-> close)

return(dev-> info-> close(dev));

return(-1);

}

这允许将许多不同的子系统插入同一个界面,

并且特别有用,例如,在自定义VFS子系统中,

.. ..

例如,
,我在VFS API上做了一次我称之为''VFILE'',并且,除了我在一点上重写它(内部,

前端API保持或多或少不变),这个API至少在十年左右一直在使用

(这几乎是

我的项目,以及我的第一个''正式''API之一。)


我记得很久以前我最初写的是RDBMS类型

项目(这是我在中学时回来的,或者我认为......)。 (该死的,

中学很久以前......)。

a typical approach is to make use of structs filled with function pointers.
these exist per-type, and are referenced by the specific open instances.

struct device_info_s {
int (*close)(device *dev);
int (*read)(device *dev, void *data, unsigned int size);
int (*write)(device *dev, const void *data, unsigned int size);
};

the frontend functions then dispatch through this struct.

int device_close (device *dev)
{
if(dev->info->close)
return(dev->info->close(dev));
return(-1);
}

this allows plugging lots of different subsystems into the same interface,
and is especially useful, for example, in things like custom VFS subsystems,
....

for example, I did this at one point for a VFS API I called ''VFILE'', and,
apart from the fact that I rewrote it at one point (the internals, the
frontend API remained more or less unchanged), this API has remained in use
for at least around a decade (this is pretty much some of the oldest code in
my projects, and one of my first ''formalized'' APIs).

from what I remember, I originally wrote it long ago for an RDBMS type
project (this was back when I was in middle school or so I think...). (damn,
middle school was a long time ago...).


我想移动共享代码到公共头和源文件

并使特定于设备的函数调用常用函数。但是我应该用下面的typdef做什么,因为在我的情况下两个结构都是相同的

。但是我想向图书馆的用户隐藏它。


/ * common.h(仅供内部使用)* /


struct device {

/ *这里的一些数据* /

};


int device_open(device ** dev,const char * name);


/ * device1.h(public)* /

typedef struct device1 device1;

int device1_open (device1 ** dev,const char * name);

...


/ * device2.h(public)* /

typedef struct device2 device2;

int device1_open(device1 ** dev,const char * name);

...
I was thinking to move the shared code to a common header and source file
and make the device-specific functions call the common functions. But what
should I do with the typdefs below, because both structs would be the same
in my case. But I would like to hide that from the user of the library.

/* common.h (for internal use only) */

struct device {
/* some data here */
};

int device_open (device **dev, const char *name);

/* device1.h (public) */
typedef struct device1 device1;
int device1_open (device1 **dev, const char *name);
...

/* device2.h (public) */
typedef struct device2 device2;
int device1_open (device1 **dev, const char *name);
...



不必要的API碎片是很难看的,特别是如果你将来可能会期待更多

...


unnecessary API fragmentation is ugly, especially if you might expect more
of it in the future...

Malcolm McLean写道:
Malcolm McLean wrote:

" Jef Driesen" < je ******** @ hotmail.com.invalidwrote in message
"Jef Driesen" <je********@hotmail.com.invalidwrote in message

>我正在写一个库(与一个号码进行通信)设备上的设备,并对设计有一些疑问。我现在有一个
标题和源文件,如下所示:

/ * device.h * /
typedef struct device device;

int device_open( device ** dev,const char * name);
int device_close(device * dev);
int device_read(device * dev,void * data,unsigned int size);
int device_write( device * dev,const void * data,unsigned int size);
>I''m writing a library (to communicate with a number of devices over a
serial port) and have some questions about the design. I have now a
header and source file like this:

/* device.h */
typedef struct device device;

int device_open (device **dev, const char *name);
int device_close (device *dev);
int device_read (device *dev, void *data, unsigned int size);
int device_write (device *dev, const void *data, unsigned int size);



从标准库中取出一本书。


FILE * fp = fopen(" filename.txt"," w");

if(!fp)

/ * it failed * /

fprintf(fp," This file works\\\
");

fclose(fp);


同样


typedef struct device DEVICE;


DEVICE * dev = device_open(" Fred");

if(!dev)

/ *你的设备没有打开* /

device_write(dev,我的名字是弗雷德,15);

device_close(DEV);

Take a book out of the standard library.

FILE *fp = fopen("filename.txt", "w");
if(!fp)
/* it failed */
fprintf(fp, "This file works\n");
fclose(fp);

Similarly

typedef struct device DEVICE;

DEVICE *dev = device_open("Fred");
if(!dev)
/* your device didn''t open */
device_write(dev, "my name is Fred", 15);
device_close(dev);



我的问题不是关于使用

返回值或输出参数返回指针的讨论。我确实选择了最后一个选项

,以便能够直接返回错误代码。这也使错误处理open函数与其他函数类似。

My question was not about the discussion to return the pointer with the
return value or with an output parameter. I did choose the last option
to be able to return an error code directly. This also makes the error
handling of the open function similar to the other functions.


这篇关于API设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆