大话设计模式C语言之桥接模式

桥接模式

桥接模式(Bridge Pattern)是结构型设计模式,主要通过将抽象部分与实现部分分离,使得二者可以独立变化分别使用。

案例代码

抽象部分

抽象部分(Abstraction)提供高层控制逻辑,依赖于完成底层实际工作的实现对象。

显示接口 display.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef DISPLAY_H
#define DISPLAY_H

#include "display_driver.h"

typedef struct Display Display;

Display* display_create(DisplayDriverType type);
void display_destroy(Display *display);

/* 桥接接口 */
void display_draw_circle(Display *display, int x,int y,int r);

#endif

显示实现 display.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdlib.h>
#include "display.h"

struct Display
{
DisplayDriver *driver;
};

Display *display_create(DisplayDriverType type)
{
Display *d = malloc(sizeof(Display));
if (!d)
return NULL;

d->driver = display_driver_create(type);
if (!d->driver)
{
free(d);
return NULL;
}
return d;
}

void display_destroy(Display *display)
{
if (!display)
return;

display_driver_destroy(display->driver);
free(display);
}

void display_draw_circle(Display *display, int x, int y, int r)
{
if (!display)
return;

display_driver_draw_circle(display->driver,
x, y, r);
}

精确抽象

精确抽象(Refined Abstraction)提供控制逻辑的变体。与其父类一样,它们通过通用实现接口与不同的实现进行交互。

精确抽象接口 circle_display.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef CIRCLE_DISPLAY_H
#define CIRCLE_DISPLAY_H

#include "display.h"

typedef struct CircleDisplay CircleDisplay;

CircleDisplay* circle_display_create(DisplayDriverType type, int x, int y, int radius);
void circle_display_draw(CircleDisplay *circle);
void circle_display_destroy(CircleDisplay *circle);

#endif

精确抽象实现 circle_display.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "circle_display.h"
#include <stdlib.h>

struct CircleDisplay
{
Display *display; /* 组合 */
int x;
int y;
int radius;
};

CircleDisplay *circle_display_create(DisplayDriverType type, int x, int y, int r)
{
CircleDisplay *c = malloc(sizeof(CircleDisplay));
if (!c)
return NULL;

c->display = display_create(type);
if (!c->display)
{
free(c);
return NULL;
}

c->x = x;
c->y = y;
c->radius = r;

return c;
}

void circle_display_draw(CircleDisplay *circle)
{
if (!circle)
return;

display_draw_circle(circle->display,
circle->x,
circle->y,
circle->radius);
}

void circle_display_destroy(CircleDisplay *circle)
{
if (!circle)
return;

display_destroy(circle->display);
free(circle);
}

实现部分

实现部分(Implementation)为所有具体实现声明通用接口。抽象部分仅能通过在这里声明的方法与实现对象交互。抽象部分可以列出和实现部分一样的方法,但是抽象部分通常声明一些复杂行为,这些行为依赖于多种由实现部分声明的原语操作。

显示驱动接口 display_driver.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef DISPLAY_DRIVER_H
#define DISPLAY_DRIVER_H

typedef struct DisplayDriver DisplayDriver;

/* 枚举具体实现类型 */
typedef enum {
DISPLAY_DRIVER_SPI = 0,
DISPLAY_DRIVER_I2C
} DisplayDriverType;

/* 创建与销毁 */
DisplayDriver* display_driver_create(DisplayDriverType type);
void display_driver_destroy(DisplayDriver *driver);

/* 实现接口 */
void display_driver_draw_circle(DisplayDriver *driver, int x, int y, int radius);

#endif

某种具体驱动 display_driver.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <stdlib.h>
#include "display_driver.h"

/* ===== 私有结构 ===== */

struct DisplayDriver
{
void (*draw_circle)(int, int, int);
};

/* ===== SPI 实现 ===== */

static void spi_draw_circle(int x, int y, int r)
{
printf("[SPI] Draw Circle (%d,%d) r=%d\n", x, y, r);
}

/* ===== I2C 实现 ===== */

static void i2c_draw_circle(int x, int y, int r)
{
printf("[I2C] Draw Circle (%d,%d) r=%d\n", x, y, r);
}

/* ===== 工厂创建 ===== */

DisplayDriver *display_driver_create(DisplayDriverType type)
{
DisplayDriver *driver = malloc(sizeof(DisplayDriver));
if (!driver)
return NULL;

switch (type)
{
case DISPLAY_DRIVER_SPI:
driver->draw_circle = spi_draw_circle;
break;
case DISPLAY_DRIVER_I2C:
driver->draw_circle = i2c_draw_circle;
break;
default:
free(driver);
return NULL;
}

return driver;
}

void display_driver_destroy(DisplayDriver *driver)
{
if (driver)
free(driver);
}

void display_driver_draw_circle(DisplayDriver *driver, int x, int y, int radius)
{
if (driver && driver->draw_circle)
driver->draw_circle(x, y, radius);
}

测试客户端代码 main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "circle_display.h"

int main(void)
{
CircleDisplay *c1 = circle_display_create(DISPLAY_DRIVER_SPI, 10, 20, 5);

CircleDisplay *c2 = circle_display_create(DISPLAY_DRIVER_I2C, 30, 40, 8);

circle_display_draw(c1);
circle_display_draw(c2);

circle_display_destroy(c1);
circle_display_destroy(c2);

while (1);
return 0;
}

总结

   桥接模式可以创建与平台无关的程序,客户端代码仅与高层抽象部分交互,而无需了解底层实现。即使新增抽象部分和实现部分它们之间不会相互影响。抽象部分专注于处理高层逻辑,实现部分处理平台细节。
  如果你需要在运行时切换不同实现方法,可使用桥接模式。当然并不是说一定要实现这一点,桥接模式可替换抽象部分中的实现对象,具体操作就和给成员变量赋新值一样简单。最后一点是很多人混淆桥接模式和策略模式的主要原因。设计模式并不仅是一种对类进行组织的方式,它还能用于沟通意图和解决问题。