桥模式
1 模拟场景
熟悉设备驱动程序的同学都知道,通常情况下设备驱动程序需要同时操作总线控制器和外设来实现对外设的访问。
以通过SPI总线访问外设为例。
假设SPI控制器1和外设1,可以按如下方式实现设备驱动程序:
SPI_Adaptor1_Client1_Write()
{
// 操作SPI控制器1...
// 操作SPI外设1...
// 操作SPI控制器1...
// 操作SPI外设1...
// ...
}
假设SPI控制器1和外设2,则可以按如下方式实现设备驱动程序:
SPI_Adaptor1_Client2_Write()
{
// 操作SPI控制器1...
// 操作SPI外设2...
// 操作SPI控制器1...
// 操作SPI外设2...
// ...
}
假设SPI控制器2和外设1,则可以按如下方式实现设备驱动程序:
SPI_Adaptor2_Client1_Write()
{
// 操作SPI控制器2...
// 操作SPI外设1...
// 操作SPI控制器2...
// 操作SPI外设1...
// ...
}
假设SPI控制器2和外设2,则可以按如下方式实现设备驱动程序:
SPI_Adaptor2_Client2_Write()
{
// 操作SPI控制器2...
// 操作SPI外设2...
// 操作SPI控制器2...
// 操作SPI外设2...
// ...
}
以此类推,如果有m个控制器和n个外设,就需要m*n份代码实现。很明显这里存在大量重复代码,我们有没有办法只用m+n份代码来实现?
首先,我们看下需要m*n份代码实现的症结在哪里?
关键在于每份代码都存在两个变化维度:一个是SPI总线控制器的变化,另一个是SPI外设的变化。所以,我们可以在“编译时”将两个变化维度拆分开,分别提供两个变化维度单独的代码,再到“运行时”将两个维度组合起来。按这种方式,就只需要m+n份代码实现。
这就是桥模式的思想。
说明一下:
Linux设备驱动程序也是按这种思想实现的。
不过本文讲的是设计模式,不是Linux设备驱动程序,所以本文给出的代码示例是按GOF《设计模式》一书中的描述来实现的,跟Linux源码在实现层面并不一致。所以,要学习Linux设备驱动程序的朋友还请自行查看Linux源码,以免被误导,但两者在思想上是一直的。
2 桥模式简介
GOF《设计模式》一书对桥模式的描述是:桥模式将抽象部分与它的实现部分分离,使他们都可以独立变化。
我个人觉得这句话不太好理解。在我看来,桥模式将多个变化维度(本文中设备驱动程序的例子有两个变化维度)分开,使多个维度可以独立变化,再在“运行时”将多个维度“组合”在一起。
3 使用桥模式实现SPI设备驱动程序
参与者
- SpiSystem
定义SPI设备驱动程序接口,包括SPI外设的操作接口,同时维护一个指向SPI控制器操作对象的指针
- SpiSystemForClient1 / SpiSystemForClient2
实现由SpiSystem定义的接口
- Adaptor
定义SPI控制器操作接口
- Adaptor1 / Adaptor2
实现SPI控制器操作接口
UML
SpiSystem示例代码
spi_system.h
#ifndef SPI_SYSTEM_H
#define SPI_SYSTEM_H
#include "adaptor.h"
struct SpiSystem {
struct Adaptor *adaptor;
void (*SpiOperation)(struct SpiSystem *this);
void (*ClientOperation)(struct SpiSystem *this);
};
#endif
SpiSystemForClient1示例代码
spi_system_for_client1.h
#ifndef SPI_SYSTEM_FOR_CLIENT1_H
#define SPI_SYSTEM_FOR_CLIENT1_H
#include "spi_system.h"
// 构造函数
void SpiSystemForClient1(struct SpiSystem *this, struct Adaptor *adaptor);
// 析构函数
void _SpiSystemForClient1(struct SpiSystem *this);
#endif
spi_system_for_client1.c
#include <stdio.h>
#include "spi_system_for_client1.h"
static void ClientOperation(struct SpiSystem *this)
{
printf(" 操作SPI外设1...\n");
}
static void SpiOperation(struct SpiSystem *this)
{
this->adaptor->AdaptorOperation(this->adaptor);
this->ClientOperation(this);
this->adaptor->AdaptorOperation(this->adaptor);
this->ClientOperation(this);
printf(" ...\n");
}
// 构造函数
void SpiSystemForClient1(struct SpiSystem *this, struct Adaptor *adaptor)
{
this->adaptor = adaptor;
this->SpiOperation = SpiOperation;
this->ClientOperation = ClientOperation;
}
// 析构函数
void _SpiSystemForClient1(struct SpiSystem *this)
{
this->adaptor = NULL;
this->SpiOperation = NULL;
this->ClientOperation = NULL;
}
SpiSystemForClient2示例代码
spi_system_for_client2.h
#ifndef SPI_SYSTEM_FOR_CLIENT2_H
#define SPI_SYSTEM_FOR_CLIENT2_H
#include "spi_system.h"
// 构造函数
void SpiSystemForClient2(struct SpiSystem *this, struct Adaptor *adaptor);
// 析构函数
void _SpiSystemForClient2(struct SpiSystem *this);
#endif
spi_system_for_client2.c
#include <stdio.h>
#include "spi_system_for_client2.h"
static void ClientOperation(struct SpiSystem *this)
{
printf(" 操作SPI外设2...\n");
}
static void SpiOperation(struct SpiSystem *this)
{
this->adaptor->AdaptorOperation(this->adaptor);
this->ClientOperation(this);
this->adaptor->AdaptorOperation(this->adaptor);
this->ClientOperation(this);
printf(" ...\n");
}
// 构造函数
void SpiSystemForClient2(struct SpiSystem *this, struct Adaptor *adaptor)
{
this->adaptor = adaptor;
this->SpiOperation = SpiOperation;
this->ClientOperation = ClientOperation;
}
// 析构函数
void _SpiSystemForClient2(struct SpiSystem *this)
{
this->adaptor = NULL;
this->SpiOperation = NULL;
this->ClientOperation = NULL;
}
Adaptor示例代码
adaptor.h
#ifndef ADAPTOR_H
#define ADAPTOR_H
struct Adaptor {
void (*AdaptorOperation)(struct Adaptor *this);
};
#endif
Adaptor1示例代码
adaptor1.h
#ifndef ADAPTOR1_H
#define ADAPTOR1_H
#include "adaptor.h"
// 构造函数
void Adaptor1(struct Adaptor *this);
// 析构函数
void _Adaptor1(struct Adaptor *this);
#endif
adaptor1.c
#include <stdio.h>
#include "adaptor1.h"
static void AdaptorOperation(struct Adaptor *this)
{
printf(" 操作SPI控制器1...\n");
}
// 构造函数
void Adaptor1(struct Adaptor *this)
{
this->AdaptorOperation = AdaptorOperation;
}
// 析构函数
void _Adaptor1(struct Adaptor *this)
{
this->AdaptorOperation = NULL;
}
Adaptor2示例代码
adaptor2.h
#ifndef ADAPTOR2_H
#define ADAPTOR2_H
#include "adaptor.h"
// 构造函数
void Adaptor2(struct Adaptor *this);
// 析构函数
void _Adaptor2(struct Adaptor *this);
#endif
adaptor2.c
#include <stdio.h>
#include "adaptor2.h"
static void AdaptorOperation(struct Adaptor *this)
{
printf(" 操作SPI控制器2...\n");
}
// 构造函数
void Adaptor2(struct Adaptor *this)
{
this->AdaptorOperation = AdaptorOperation;
}
// 析构函数
void _Adaptor2(struct Adaptor *this)
{
this->AdaptorOperation = NULL;
}
客户端代码示例
#include <stdio.h>
#include "adaptor1.h"
#include "spi_system_for_client1.h"
void main()
{
struct Adaptor adapter1;
Adaptor1(&adapter1);
struct Adaptor adapter2;
Adaptor2(&adapter2);
struct SpiSystem spiSystemForClient1;
struct SpiSystem spiSystemForClient2;
printf("实现SPI_Adaptor1_Client1_Write:\n");
SpiSystemForClient1(&spiSystemForClient1, &adapter1);
spiSystemForClient1.SpiOperation(&spiSystemForClient1);
printf("\n");
printf("实现SPI_Adaptor1_Client2_Write:\n");
SpiSystemForClient2(&spiSystemForClient2, &adapter1);
spiSystemForClient2.SpiOperation(&spiSystemForClient2);
printf("\n");
printf("实现SPI_Adaptor2_Client1_Write:\n");
SpiSystemForClient1(&spiSystemForClient1, &adapter2);
spiSystemForClient1.SpiOperation(&spiSystemForClient1);
printf("\n");
printf("实现SPI_Adaptor2_Client2_Write:\n");
SpiSystemForClient2(&spiSystemForClient2, &adapter2);
spiSystemForClient2.SpiOperation(&spiSystemForClient2);
printf("\n");
}
客户端显示示例
-bash-4.2# ./test
实现SPI_Adaptor1_Client1_Write:
操作SPI控制器1...
操作SPI外设1...
操作SPI控制器1...
操作SPI外设1...
...
实现SPI_Adaptor1_Client2_Write: 操作SPI控制器1...
操作SPI外设2...
操作SPI控制器1...
操作SPI外设2...
...
实现SPI_Adaptor2_Client1_Write: 操作SPI控制器2...
操作SPI外设1...
操作SPI控制器2...
操作SPI外设1...
...
实现SPI_Adaptor2_Client2_Write: 操作SPI控制器2...
操作SPI外设2...
操作SPI控制器2...
操作SPI外设2...
...