大话设计模式C语言之中介者模式

中介者模式

中介者模式(Mediator Pattern)是一种行为设计模式,能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作,从而降低它们间的耦合。

案例代码

中介者

中介者接口 mediator.h

中介者(Mediator)接口声明了与组件交流的方法,但通常仅包括一个通知方法。组件可将任意上下文(包括自己的对象)作为该方法的参数,只有这样接收组件和发送者类之间才不会耦合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef MEDIATOR_H
#define MEDIATOR_H

typedef struct HomeMediator HomeMediator;
typedef struct Light Light;
typedef struct Fan Fan;
typedef struct Sensor Sensor;

HomeMediator *home_mediator_create(void);
void home_mediator_destroy(HomeMediator *m);

void home_mediator_register_light(HomeMediator *m, Light *light);
void home_mediator_register_fan(HomeMediator *m, Fan *fan);
void home_mediator_register_sensor(HomeMediator *m, Sensor *sensor);

/* 组件通知接口 */
void home_mediator_notify(HomeMediator *m, void *sender, const char *event);

#endif

具体中介者 home_mediator.c

具体中介者(Concrete Mediator)封装了多种组件间的关系。具体中介者通常会保存所有组件的引用并对其进行管理,甚至有时会对其生命周期进行管理。

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
#include <stdlib.h>
#include <string.h>
#include "mediator.h"
#include "light.h"
#include "fan.h"

struct HomeMediator {
Light *light;
Fan *fan;
Sensor *sensor;
};

HomeMediator *home_mediator_create(void)
{
return calloc(1, sizeof(HomeMediator));
}

void home_mediator_destroy(HomeMediator *m)
{
if (m) free(m);
}

void home_mediator_register_light(HomeMediator *m, Light *light)
{
if (m) m->light = light;
}

void home_mediator_register_fan(HomeMediator *m, Fan *fan)
{
if (m) m->fan = fan;
}

void home_mediator_register_sensor(HomeMediator *m, Sensor *sensor)
{
if (m) m->sensor = sensor;
}

void home_mediator_notify(HomeMediator *m, void *sender, const char *event)
{
if (!m || !event) return;

if (strcmp(event, "MOTION") == 0 && sender == m->sensor) {

if (m->light) light_on(m->light);
if (m->fan) fan_on(m->fan);
}
}

组件

组件(Component 是各种包含业务逻辑的类。每个组件都有一个指向中介者的引用,该引用被声明为中介者接口类型。组件不知道中介者实际所属的类,因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。

组件并不知道其他组件的情况。如果组件内发生了重要事件,它只能通知中介者。中介者收到通知后能轻易地确定发送者,这或许已足以判断接下来需要触发的组件了。对于组件来说中介者看上去完全就是一个黑箱。发送者不知道最终会由谁来处理自己的请求,接收者也不知道最初是谁发出了请求。

传感器模块
sensor.h
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef SENSOR_H
#define SENSOR_H

typedef struct Sensor Sensor;
typedef struct HomeMediator HomeMediator;

Sensor *sensor_create(HomeMediator *m);
void sensor_destroy(Sensor *s);

void sensor_detect_motion(Sensor *s);

#endif

sensor.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
#include <stdio.h>
#include <stdlib.h>
#include "sensor.h"
#include "mediator.h"

struct Sensor {
HomeMediator *mediator;
};

Sensor *sensor_create(HomeMediator *m)
{
Sensor *s = calloc(1, sizeof(Sensor));
if (!s) return NULL;
s->mediator = m;
return s;
}

void sensor_destroy(Sensor *s)
{
if (s) free(s);
}

void sensor_detect_motion(Sensor *s)
{
if (!s || !s->mediator) return;

printf("Sensor: Motion detected\n");

home_mediator_notify(s->mediator, s, "MOTION");
}

灯光模块
light.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef LIGHT_H
#define LIGHT_H

typedef struct Light Light;
typedef struct HomeMediator HomeMediator;

Light *light_create(HomeMediator *m);
void light_destroy(Light *l);

void light_on(Light *l);
void light_off(Light *l);

#endif

light.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 <stdio.h>
#include <stdlib.h>
#include "light.h"

struct Light {
HomeMediator *mediator;
int state;
};

Light *light_create(HomeMediator *m)
{
Light *l = calloc(1, sizeof(Light));
if (!l) return NULL;
l->mediator = m;
l->state = 0;
return l;
}

void light_destroy(Light *l)
{
if (l) free(l);
}

void light_on(Light *l)
{
if (!l) return;
if (!l->state) {
l->state = 1;
printf("Light ON\n");
}
}

void light_off(Light *l)
{
if (!l) return;
if (l->state) {
l->state = 0;
printf("Light OFF\n");
}
}

风扇模块
fan.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef FAN_H
#define FAN_H

typedef struct Fan Fan;
typedef struct HomeMediator HomeMediator;

Fan *fan_create(HomeMediator *m);
void fan_destroy(Fan *f);

void fan_on(Fan *f);
void fan_off(Fan *f);

#endif

fan.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 <stdio.h>
#include <stdlib.h>
#include "fan.h"

struct Fan {
HomeMediator *mediator;
int state;
};

Fan *fan_create(HomeMediator *m)
{
Fan *f = calloc(1, sizeof(Fan));
if (!f) return NULL;
f->mediator = m;
f->state = 0;
return f;
}

void fan_destroy(Fan *f)
{
if (f) free(f);
}

void fan_on(Fan *f)
{
if (!f) return;
if (!f->state) {
f->state = 1;
printf("Fan ON\n");
}
}

void fan_off(Fan *f)
{
if (!f) return;
if (f->state) {
f->state = 0;
printf("Fan OFF\n");
}
}

测试客户端代码 main.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
#include "mediator.h"
#include "light.h"
#include "fan.h"
#include "sensor.h"

int main(void)
{
HomeMediator *mediator = home_mediator_create();

Light *light = light_create(mediator);
Fan *fan = fan_create(mediator);
Sensor *sensor = sensor_create(mediator);

home_mediator_register_light(mediator, light);
home_mediator_register_fan(mediator, fan);
home_mediator_register_sensor(mediator, sensor);

/* 模拟触发 */
sensor_detect_motion(sensor);

/* 资源释放 */
sensor_destroy(sensor);
fan_destroy(fan);
light_destroy(light);
home_mediator_destroy(mediator);

while(1);
return 0;
}

总结

   中介者的出现减少了各个组件间的耦合,使得可以独立的改变和复用各个组件。但是由于具体的中介者控制集中化,使得将交付复杂性变为了中介者的复杂性,最后可能会产生一个过于复杂的中介者类。中介者一般应用于一组对象以定义良好但是复杂的方式进行通信的场合。