10 modèles de conception _ modèle de combinaison _ implémentation du langage C

Mode combiné

1. Introduction

Le mode de combinaison combine des objets dans une structure arborescente pour représenter une structure hiérarchique «partielle-entière». Le mode combiné permet aux utilisateurs d'avoir une cohérence dans l'utilisation d'objets uniques et d'objets combinés.

Le mode combiné est très simple à comprendre. Il est appliqué à la combinaison d'objets avec une structure arborescente.

L'avantage est: utiliser un ensemble de méthodes d'appel pour traiter chaque objet de la combinaison d'objets et permettre d'augmenter librement le nombre d'objets.

2 Scène de simulation

La structure de répertoires du système de fichiers explique une structure de répertoires très typique.

Cet article suppose la forme suivante de système de fichiers et l'utilise comme exemple:

Insérez la description de l'image ici

3 Utilisez le mode combiné pour implémenter le système de fichiers

Participant

  1. Composant: FileSystemNode

Déclarer les interfaces pour les nœuds dans le système de fichiers

  1. Feuille: Fichier

Objet fichier. Dans le système de fichiers, l'objet fichier est l'objet feuille du système de fichiers (c'est-à-dire qu'il est impossible d'ajouter des nœuds enfants à l'objet fichier)

  1. Dossier : composite

Objet dossier

UML

Insérez la description de l'image ici

Exemple de code 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

Exemple de code de fichier

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

fichier.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;
}

Exemple de code de dossier

dossier.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

dossier.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;
}

Exemple de code client

#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);
}

Exemple d'affichage du client

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

4 Analyse de la transparence et de la sécurité du mode combiné

À partir de l'UML et de l'exemple de code ci-dessus, il n'est pas difficile de trouver que pour File, Add () et Remove () n'ont pas de sens et peuvent même être considérés comme erronés. Bien que Add () et Remove () que nous avons implémentés pour File soient vides et affichent des messages d'erreur, cela peut toujours introduire des erreurs (la tentative d'ajout de nœuds enfants à File est en soi une erreur).

Alors, comment résoudre ce problème?

La solution est la suivante: puisque File n'a pas besoin de Add () et Remove (), alors nous devons déplacer Add () et Remove () de FileSystemNode vers Folder .

Mais cela entraîne un nouveau problème: le client ne peut pas utiliser exactement la même méthode lors de l'appel de File et Folder , car les méthodes qu'ils fournissent ne sont pas exactement les mêmes.

Les deux schémas ci-dessus ont leurs propres avantages, mais ils ne sont pas parfaits. Il n'y a pas de solution parfaite aux deux problèmes ci-dessus .

Pour le premier schéma, en raison de sa transparence (le client ne peut pas faire la distinction entre Fichier et Dossier), nous l'appelons un mode de combinaison transparent.

Pour ce dernier schéma, parce qu'il est plus sécurisé (le client n'appellera pas une méthode dénuée de sens par erreur), nous l'appelons un mode de combinaison sécurisé.

Habituellement, nous choisissons une solution en fonction des exigences de la scène en matière de transparence et de sécurité, ainsi que des préférences personnelles.

Ce qui suit donne l'UML du mode de combinaison sûr pour la comparaison avec le mode de combinaison transparent:

Insérez la description de l'image ici

Lors de l'utilisation du mode de combinaison sans échec, le client a besoin de savoir si le nœud est File ou Folder via GetType (), et ce n'est que lorsque le nœud est Folder qu'il peut appeler Add () et Remove ().

Je suppose que tu aimes

Origine blog.csdn.net/weixin_46826913/article/details/107305421
conseillé
Classement