数据再抽象

最后更新于:2022-04-01 06:25:42

## 数据再抽象 上一节的代码有些冗长,我们可以尝试对其进行精简。首先看下面这三个结构体及其 `create` 函数: ~~~ struct point { double x; double y; }; struct rectangle { double width; double height; }; struct circle { struct point *center; double radius; }; struct chain_node_shape { struct rectangle *body; struct circle *holes[2] ; }; struct point * create_point(double x, double y) { struct point *ret = malloc(sizeof(struct point)); ret->x = x; ret->y = y; return ret; } struct circle * create_circle(struct point *center, double radius) { struct circle *ret = malloc(sizeof(struct circle)); ret->center = center; ret->radius = radius; return ret; } struct rectangle * create_rectangle(double w, double h) { struct rectangle *ret = malloc(sizeof(struct rectangle)); ret->width = w; ret->height = h; return ret; } struct chain_node_shape * create_chain_node_shape(struct circle *c1, struct circle *c2, struct rectangle *rect) { struct chain_node_shape *ret = malloc(sizeof(struct chain_node_shape)); ret->body = rect; ret->holes[0] = c1; ret->holes[1] = c2; return ret; } ~~~ 显然,这些代码长的太像了!那四个结构体都是存储两个成员的结构体,而相应的 `create` 函数也无非是将函数所接受的参数保存到结构体成员中。有没有办法用很少的代码来表示它们?有! 既然每个结构体都保存 2 个成员,那么我们就先将上述代码删掉,然后定义一个 `pair` 类型的结构体: ~~~ struct pair { void *first; void *second; }; ~~~ 在 `pair` 结构体中,我们用了两个 `void *` 指针,只有如此我们方能很自信的说 `pair` 可以存储任意类型的两个数据。接下来,只需修改 `create_chain_node` 函数的定义: ~~~ struct chain_node * create_chain_node(void) { double *left_x = malloc(sizeof(double)); double *left_y = malloc(sizeof(double)); *left_x = 1.0; *left_y = 1.0; struct pair *left_center = malloc(sizeof(struct pair)); left_center->first = left_x; left_center->second = left_y; double *left_radius = malloc(sizeof(double)); *left_radius = 0.5; struct pair *left_hole = malloc(sizeof(struct pair)); left_hole->first = left_center; left_hole->second = left_radius; double *right_x = malloc(sizeof(double)); double *right_y = malloc(sizeof(double)); *right_x = 9.0; *right_y = 1.0; struct pair *right_center = malloc(sizeof(struct pair)); right_center->first = right_x; right_center->second = right_y; double *right_radius = malloc(sizeof(double)); *right_radius = 0.5; struct pair *right_hole = malloc(sizeof(struct pair)); right_hole->first = right_center; right_hole->second = right_radius; struct pair *holes = malloc(sizeof(struct pair)); holes->first = left_hole; holes->second = right_hole; struct pair *body = malloc(sizeof(struct pair)); double *width = malloc(sizeof(double)); *width = 10.0; double *height = malloc(sizeof(double)); *height = 2.0; body->first = width; body->second = height; struct pair *shape = malloc(sizeof(struct pair)); shape->first = body; shape->second = holes; struct chain_node *ret = malloc(sizeof(struct chain_node)); ret->prev = NULL; ret->next = NULL; ret->shape = shape; return ret; } ~~~ 我勇敢的承认这个基于 `struct pair` 的 `create_chain_node` 函数太丑陋了,但是我们总算是消除了大量的结构体及其构造函数了,而且整体代码量减少了大约 1/6。 仔细观察上述代码,显然下面的三段代码存在着高度的重复: ~~~ double *left_x = malloc(sizeof(double)); double *left_y = malloc(sizeof(double)); *left_x = 1.0; *left_y = 1.0; struct pair *left_center = malloc(sizeof(struct pair)); left_center->first = left_x; left_center->second = left_y; double *right_x = malloc(sizeof(double)); double *right_y = malloc(sizeof(double)); *right_x = 9.0; *right_y = 1.0; struct pair *right_center = malloc(sizeof(struct pair)); right_center->first = right_x; right_center->second = right_y; struct pair *body = malloc(sizeof(struct pair)); double *width = malloc(sizeof(double)); *width = 10.0; double *height = malloc(sizeof(double)); *height = 2.0; body->first = width; body->second = height; ~~~ 这三段代码都在向 `pair` 结构体中存入两个 `double *` 类型的数据。既然如此,我们可以专门写一个函数,让它生成面向`double *` 的 `pair` 结构体,即: ~~~ struct pair * pair_for_double_type(double x, double y) { struct pair *ret = malloc(sizeof(struct pair)); double *first = malloc(sizeof(double)); double *second = malloc(sizeof(double)); *first = x; *second = y; ret->first = first; ret->second = first; return ret; } ~~~ 然后再次重构 `create_chain_node` 函数: ~~~ struct chain_node * create_chain_node(void) { struct pair *left_center = pair_for_double_type(1.0, 1.0); double *left_radius = malloc(sizeof(double)); *left_radius = 0.5; struct pair *left_hole = malloc(sizeof(struct pair)); left_hole->first = left_center; left_hole->second = left_radius; struct pair *right_center = pair_for_double_type(9.0, 1.0); double *right_radius = malloc(sizeof(double)); *right_radius = 0.5; struct pair *right_hole = malloc(sizeof(struct pair)); right_hole->first = right_center; right_hole->second = right_radius; struct pair *holes = malloc(sizeof(struct pair)); holes->first = left_hole; holes->second = right_hole; struct pair *body = pair_for_double_type(10.0, 1.0); struct pair *shape = malloc(sizeof(struct pair)); shape->first = body; shape->second = holes; struct chain_node *ret = malloc(sizeof(struct chain_node)); ret->prev = NULL; ret->next = NULL; ret->shape = shape; return ret; } ~~~
';