09设计模式_装饰模式_C语言实现

装饰模式

1 模拟场景

假设我们需要处理一些数据。

被处理的数据按类型分为内存数据、文件数据。

处理方法包括基本的数据处理功能(如: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个。

这就是装饰模式的思想。扩展功能就像一个个装饰品,可以把装饰品任意组合并添加到数据类型上。

2 装饰模式简介

在我们需要给某个对象动态地添加功能,且被添加的多种功能存在组合添加的情况时,如果我们使用继承机制来添加功能,我们需要实现的类的个数非常庞大。因为继承机制只能在“编译时”静态添加功能,使得我们需要将添加功能的所有组合情况全部枚举出来。

装饰模式采取组合机制,而非继承机制,在“运行时”动态地给对象添加功能。用装饰模式实现上述场景可以消除重复代码,极大的减少子类个数。

3 使用装饰模式实现“数据处理”

参与者

  1. Component: Data

定义数据处理接口

  1. ConcreteComponent: MemData、FileData

定义具体的数据对象

  1. Decorator: ExtraDataOperation

为扩展功能定义一个与Data对象一致的接口,并维持一个指向Data对象的指针

  1. ConcreteDecorator: CryptoOperation、SignOperation

定义向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 <stdio.h> 
#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 <stdio.h> 
#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 <stdio.h> 
#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 <stdio.h> 
#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 <stdio.h>
#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
仅 内存数据 操作:
  内存数据操作...

给 内存数据 添加 加密操作 功能:
  内存数据操作...
  加密操作...

给 内存数据 添加 签名操作 功能:
  内存数据操作...
  签名操作...

给 内存数据 添加 加密操作 和 签名操作 功能:
  内存数据操作...
  加密操作...
  签名操作...

仅 文件数据 操作:
  内存数据操作...

给 文件数据 添加 加密操作 功能:
  内存数据操作...
  加密操作...

给 文件数据 添加 签名操作 功能:
  内存数据操作...
  签名操作...

给 文件数据 添加 加密操作 和 签名操作 功能:
  内存数据操作...
  加密操作...
  签名操作...

猜你喜欢

转载自blog.csdn.net/weixin_46826913/article/details/107144795