10 patrón de diseño _ patrón de combinación _ implementación del lenguaje C

Modo de combinación

1. Introducción

El modo de combinación combina objetos en una estructura de árbol para representar una estructura jerárquica "parte-todo". El modo combinado permite a los usuarios tener coherencia en el uso de objetos individuales y objetos combinados.

El modo de combinación es muy fácil de entender. Se aplica a la combinación de objetos con estructura de árbol.

La ventaja es: se utiliza un conjunto de métodos de llamada para procesar cada objeto en la combinación de objetos y el número de objetos se puede aumentar libremente.

2 escena de simulación

La estructura de directorios del sistema de archivos explica una estructura de directorios muy típica.

Este artículo asume la siguiente forma de sistema de archivos y lo usa como ejemplo:

Inserte la descripción de la imagen aquí

3 Utilice el modo combinado para implementar el sistema de archivos

Partícipe

  1. Componente: FileSystemNode

Declarar interfaces para nodos en el sistema de archivos

  1. Hoja: Archivo

Objeto de archivo. En el sistema de archivos, el objeto de archivo es el objeto hoja del sistema de archivos (es decir, es imposible agregar nodos secundarios al objeto de archivo)

  1. Compuesto: Carpeta

Objeto de carpeta

UML

Inserte la descripción de la imagen aquí

Código de muestra de FileSystemNode

file_system_node.h

#ifndef FILE_SYSTEM_NODE_H
#define FILE_SYSTEM_NODE_H

struct FileSystemNode {
    char nodeName[100];
    struct FileSystemNode *childList[100];
    void (*Operation)(struct FileSystemNode *this);
    void (*Add)(struct FileSystemNode *this, struct FileSystemNode *node);
    void (*Remove)(struct FileSystemNode *this, struct FileSystemNode *node);
};

#endif

Código de muestra de archivo

file.h

#ifndef FILE_H
#define FILE_H

#include "file_system_node.h"

// 构造函数
void File(struct FileSystemNode *this, char *nodeName);
// 析构函数
void _File(struct FileSystemNode *this);

#endif

file.c

#include <stdlib.h>
#include <stdio.h> 
#include <string.h>
#include "file.h"

static void Operation(struct FileSystemNode *this)
{   
    printf("操作文件 %s\n", this->nodeName);
}

static void Add(struct FileSystemNode *this, struct FileSystemNode *node)
{    
    printf("error: 文件节点,不支持增加子节点\n");
}

static void Remove(struct FileSystemNode *this, struct FileSystemNode *node)
{
    printf("error: 文件节点,不支持删除子节点\n");
}

// 构造函数
void File(struct FileSystemNode *this, char *nodeName)
{
    strcpy(this->nodeName, nodeName);
    memset(this->childList, 0, sizeof(this->childList));
    this->Operation = Operation;
    this->Add = Add;
    this->Remove = Remove;
}

// 析构函数
void _File(struct FileSystemNode *this)
{
    memset(this->nodeName, 0, sizeof(this->nodeName));
    memset(this->childList, 0, sizeof(this->childList));
    this->Operation = NULL;
    this->Add = NULL;
    this->Remove = NULL;
}

Código de muestra de carpeta

folder.h

#ifndef FOLDER_H
#define FOLDER_H

#include "file_system_node.h"

// 构造函数
void Folder(struct FileSystemNode *this, char *nodeName);
// 析构函数
void _Folder(struct FileSystemNode *this);

#endif

carpeta.c

#include <stdlib.h>
#include <stdio.h> 
#include <string.h>
#include "folder.h"

static void Operation(struct FileSystemNode *this)
{    
    printf("操作文件夹 %s\n", this->nodeName);
    
    int i;      
    for (i = 0; i < 100; i++) {
        if (this->childList[i] != NULL) {
            this->childList[i]->Operation(this->childList[i]);
        }        
    }
}

static void Add(struct FileSystemNode *this, struct FileSystemNode *node)
{
    int i;      
    for (i = 0; i < 100; i++) {
        if (this->childList[i] == NULL) {
            this->childList[i] = node;
            return;
        }
    }
    printf("error: add node fail\n");
}

static void Remove(struct FileSystemNode *this, struct FileSystemNode *node)
{
    int i;      
    for (i = 0; i < 100; i++) {
        if (this->childList[i] == node) {
            this->childList[i] = NULL;
            return;
        }
    }
    printf("error: remove node fail\n");
}

// 构造函数
void Folder(struct FileSystemNode *this, char *nodeName)
{
    strcpy(this->nodeName, nodeName);
    memset(this->childList, 0, sizeof(this->childList));
    this->Operation = Operation;
    this->Add = Add;
    this->Remove = Remove;
}

// 析构函数
void _Folder(struct FileSystemNode *this)
{
    memset(this->nodeName, 0, sizeof(this->nodeName));
    memset(this->childList, 0, sizeof(this->childList));
    this->Operation = NULL;
    this->Add = NULL;
    this->Remove = NULL;
}

Ejemplo de código de cliente

#include "folder.h"
#include "file.h"

void main()
{
    struct FileSystemNode root;
    struct FileSystemNode folder1;
    struct FileSystemNode folder2;
    struct FileSystemNode folder3;
    struct FileSystemNode file1;
    struct FileSystemNode file2;
    struct FileSystemNode file3;

    Folder(&root, "root");
    Folder(&folder1, "folder1");
    Folder(&folder2, "folder2");
    Folder(&folder3, "folder3");
    File(&file1, "file1");
    File(&file2, "file2");
    File(&file3, "file3");

    root.Add(&root, &folder1);
    root.Add(&root, &folder2);
    root.Add(&root, &file1);
    folder1.Add(&folder1, &file2);
    folder1.Add(&folder1, &file3);
    folder2.Add(&folder2, &folder3);

    root.Operation(&root);
}

Ejemplo de visualización del cliente

-bash-4.2# ./test
操作文件夹 root
操作文件夹 folder1
操作文件 file2
操作文件 file3
操作文件夹 folder2
操作文件夹 folder3
操作文件 file1

4 Análisis de transparencia y seguridad del modo combinado

A partir del código de muestra y UML anterior, no es difícil encontrar que para Archivo, Agregar () y Eliminar () no tienen sentido , e incluso se puede decir que son incorrectos. Aunque Add () y Remove () que implementamos para File están vacíos e imprimen mensajes de error, esto aún puede introducir errores (intentar agregar nodos secundarios a File es en sí mismo un error).

Entonces, ¿cómo solucionar este problema?

La solución es: dado que el archivo no necesita Add () y Remove (), entonces debemos mover Add () y Remove () de FileSystemNode a Folder .

Pero esto genera un nuevo problema: el cliente no puede usar exactamente el mismo método cuando llama a Archivo y Carpeta , porque los métodos que proporcionan no son exactamente los mismos.

Los dos esquemas anteriores tienen sus propias ventajas, pero no son perfectos. No existe una solución perfecta para los dos problemas anteriores .

Para el primer esquema, debido a su transparencia (el cliente no puede distinguir entre Archivo y Carpeta), lo llamamos modo de combinación transparente.

Para el último esquema, debido a que es más seguro (el cliente no llamará por error a un método sin sentido), lo llamamos un modo de combinación seguro.

Por lo general, elegimos una solución en función de los requisitos del escenario de transparencia y seguridad, así como de las preferencias personales.

A continuación, se muestra el UML del modo de combinación seguro para compararlo con el modo de combinación transparente:

Inserte la descripción de la imagen aquí

Cuando se usa el modo de combinación segura, el cliente necesita saber si el nodo es Archivo o Carpeta a través de GetType (), y solo cuando el nodo es Carpeta puede llamar a Add () y Remove ().

Supongo que te gusta

Origin blog.csdn.net/weixin_46826913/article/details/107305421
Recomendado
Clasificación