假设我们需要处理一些数据。
被处理的数据按类型分为内存数据、文件数据。
处理方法包括基本的数据处理功能(如:read、write),还有加密、签名等扩展功能。扩展功能是指可根据场景选择的功能,即:有些场景不需要加密、签名处理,有些场景仅需要加密处理,有些场景仅需要签名处理,还有些场景需要即加密又签名。
如果我们使用继承来给不同数据类型(内存数据、文件数据)添加扩展功能(加密、签名),我们需要实现多少个类呢?我们来看下面的示意图:
从示意图中我们可以看到,如果有m中数据类型,n种扩展功能,那么:
第一层:所有类的基类(Data)共1个类
第二层:m种数据类型类(MemData、FileData)共m个类
第三层:每种数据类型有 C n 1 + C n 2 + . . . + C n n C_n^1+C_n^2+...+C_n^n Cn1+Cn2+...+Cnn种扩展功能的组合,所以m中数据类型共m*n!种扩展功能的组合,共 m ∗ ( C n 1 + C n 2 + . . . + C n n ) m*(C_n^1+C_n^2+...+C_n^n) m∗(Cn1+Cn2+...+Cnn) 个类
以上示意图中,m=2,n=2,所以共 2 ∗ ( C 2 1 + C 2 2 ) = 6 2*(C_2^1+C_2^2) = 6 2∗(C21+C22)=6 个类。
随着m和n的增大,这种方法需要的类的个数以阶乘的量级急剧增大。
我们不难发现,类个数多的症结跟"桥模式"一章中遇到的问题的症结有一些相似之处。
因为扩展功能的组合关系是在“编译时”决定的,所以“编译时”需要将所有组合全部枚举出来。
如果我们将每种扩展功能分开实现,并在“运行时”根据场景需要将扩展功能一个一个添加到每种数据类型上,那么上述第三层就只需要实现n个独立的扩展功能。上述类的总个数就会减少为1+m+n个。
这就是装饰模式的思想。扩展功能就像一个个装饰品,可以把装饰品任意组合并添加到数据类型上。
在我们需要给某个对象动态地添加功能,且被添加的多种功能存在组合添加的情况时,如果我们使用继承机制来添加功能,我们需要实现的类的个数非常庞大。因为继承机制只能在“编译时”静态添加功能,使得我们需要将添加功能的所有组合情况全部枚举出来。
装饰模式采取组合机制,而非继承机制,在“运行时”动态地给对象添加功能。用装饰模式实现上述场景可以消除重复代码,极大的减少子类个数。
参与者
定义数据处理接口
定义具体的数据对象
为扩展功能定义一个与Data对象一致的接口,并维持一个指向Data对象的指针
定义向Data对象添加的功能
UML
Data示例代码
data.h
#ifndef DATA_H
#define DATA_H
struct Data {
void (*Operation)(struct Data *this);
};
#endif
MemData示例代码
mem_data.h
#ifndef MEM_DATA_H
#define MEM_DATA_H
#include "data.h"
// 构造函数
void MemData(struct Data *this);
// 析构函数
void _MemData(struct Data *this);
#endif
mem_data.c
#include
#include "mem_data.h"
static void Operation(struct Data *this)
{
printf(" 内存数据操作...\n");
}
// 构造函数
void MemData(struct Data *this)
{
this->Operation = Operation;
}
// 析构函数
void _MemData(struct Data *this)
{
this->Operation = NULL;
}
FileData示例代码
file_data.h
#ifndef FILE_DATA_H
#define FILE_DATA_H
#include "data.h"
// 构造函数
void FileData(struct Data *this);
// 析构函数
void _FileData(struct Data *this);
#endif
file_data.c
#include
#include "file_data.h"
static void Operation(struct Data *this)
{
printf(" 文件数据操作...\n");
}
// 构造函数
void FileData(struct Data *this)
{
this->Operation = Operation;
}
// 析构函数
void _FileData(struct Data *this)
{
this->Operation = NULL;
}
ExtraDataOperation示例代码
extra_data_operation.h
#ifndef EXTRA_DATA_OPERATION_H
#define EXTRA_DATA_OPERATION_H
#include "data.h"
struct ExtraDataOperation {
struct Data inheritedData;
struct Data *data;
};
#endif
CryptoOperation示例代码
crypto_operation.h
#ifndef CRYPTO_OPERATION_H
#define CRYPTO_OPERATION_H
#include "extra_data_operation.h"
struct CryptoOperation {
struct Data inheritedData;
struct Data *data;
};
// 构造函数
void CryptoOperation(struct CryptoOperation *this, struct Data *data);
// 析构函数
void _CryptoOperation(struct CryptoOperation *this);
#endif
crypto_operation.c
#include
#include "crypto_operation.h"
static void Operation(struct CryptoOperation *this)
{
this->data->Operation(this->data);
printf(" 加密操作...\n");
}
// 构造函数
void CryptoOperation(struct CryptoOperation *this, struct Data *data)
{
this->data = data;
this->inheritedData.Operation = (void(*)(struct Data *))Operation;
}
// 析构函数
void _CryptoOperation(struct CryptoOperation *this)
{
this->data = NULL;
this->inheritedData.Operation = NULL;
}
SignOperation示例代码
sign_operation.h
#ifndef SIGN_OPERATION_H
#define SIGN_OPERATION_H
#include "extra_data_operation.h"
struct SignOperation {
struct Data inheritedData;
struct Data *data;
};
// 构造函数
void SignOperation(struct SignOperation *this, struct Data *data);
// 析构函数
void _SignOperation(struct SignOperation *this);
#endif
sign_operation.c
#include
#include "sign_operation.h"
static void Operation(struct SignOperation *this)
{
this->data->Operation(this->data);
printf(" 签名操作...\n");
}
// 构造函数
void SignOperation(struct SignOperation *this, struct Data *data)
{
this->data = data;
this->inheritedData.Operation = (void(*)(struct Data *))Operation;
}
// 析构函数
void _SignOperation(struct SignOperation *this)
{
this->data = NULL;
this->inheritedData.Operation = NULL;
}
客户端代码示例
#include
#include "mem_data.h"
#include "file_data.h"
#include "crypto_operation.h"
#include "sign_operation.h"
void main()
{
struct Data memData;
struct Data fileData;
struct CryptoOperation cryptoOperation;
struct SignOperation signOperation;
printf("仅 内存数据 操作:\n");
MemData(&memData);
memData.Operation(&memData);
printf("\n");
printf("给 内存数据 添加 加密操作 功能:\n");
CryptoOperation(&cryptoOperation, &memData);
cryptoOperation.inheritedData.Operation((struct Data *)&cryptoOperation);
printf("\n");
printf("给 内存数据 添加 签名操作 功能:\n");
SignOperation(&signOperation, &memData);
signOperation.inheritedData.Operation((struct Data *)&signOperation);
printf("\n");
printf("给 内存数据 添加 加密操作 和 签名操作 功能:\n");
SignOperation(&signOperation, (struct Data *)&cryptoOperation);
signOperation.inheritedData.Operation((struct Data *)&signOperation);
printf("\n");
printf("仅 文件数据 操作:\n");
MemData(&fileData);
fileData.Operation(&fileData);
printf("\n");
printf("给 文件数据 添加 加密操作 功能:\n");
CryptoOperation(&cryptoOperation, &fileData);
cryptoOperation.inheritedData.Operation((struct Data *)&cryptoOperation);
printf("\n");
printf("给 文件数据 添加 签名操作 功能:\n");
SignOperation(&signOperation, &fileData);
signOperation.inheritedData.Operation((struct Data *)&signOperation);
printf("\n");
printf("给 文件数据 添加 加密操作 和 签名操作 功能:\n");
SignOperation(&signOperation, (struct Data *)&cryptoOperation);
signOperation.inheritedData.Operation((struct Data *)&signOperation);
printf("\n");
}
客户端显示示例
-bash-4.2# ./test
仅 内存数据 操作:
内存数据操作...
给 内存数据 添加 加密操作 功能:
内存数据操作...
加密操作...
给 内存数据 添加 签名操作 功能:
内存数据操作...
签名操作...
给 内存数据 添加 加密操作 和 签名操作 功能:
内存数据操作...
加密操作...
签名操作...
仅 文件数据 操作:
内存数据操作...
给 文件数据 添加 加密操作 功能:
内存数据操作...
加密操作...
给 文件数据 添加 签名操作 功能:
内存数据操作...
签名操作...
给 文件数据 添加 加密操作 和 签名操作 功能:
内存数据操作...
加密操作...
签名操作...