Article From:https://www.cnblogs.com/ToBeExpert/p/9682277.html

2018-09-20 16:12:07

Combination mode (Composite)

  Composite, which combines objects into a tree structure to represent the’part-whole’hierarchy. Composition patterns allow users to consistently use individual objects (i.e., leaf components) and composite objects (i.e., composite components). (for example, you can use a single word in word.Note that the tree here is a tree, without any restrictions, it can be any shape. This tree is built on the combination of objects rather than data structures.

When to use combination mode

  When you find that a requirement is part of the overall hierarchy (tree structure), and when you want users to ignore the difference between composite objects and a single object and use all objects in a unified composite structure, you should consider composite patterns.

Combinatorial mode UML class diagram

Composition patterns can be divided into two types according to different implementations: transparent mode and secure mode.

Transparent mode combination mode UML class diagram:

   In transparent composite patterns, Component is the base class for all components that apply composite patterns. It provides common methods for all subclasses in the entire pattern structure, and provides methods for managing and accessing subcomponents (such as Add, Remove, GetChild)

  LeafIn this structure, leaf nodes are represented, just like trees in data structures, leaf nodes can not have child nodes. So the obvious problem is that leaf node implementations are used to manage subcomponents: Add, Remove, GetChild are meaningless. This is the transparent combination mode.The problem.

  Composite:There is a list of Component pointer objects inside it, because in the whole schema, Composite represents a branch node, and there may be an indefinite number of branch nodes under the branch node. The purpose of this list is to preserve the child nodes of the branch node. At CoMposite implements methods for managing child nodes: Add, Remove, GetChild.

  The advantage of transparent combination mode is that it shields the difference between leaf nodes and branch nodes for client. But the client must know exactly which leaf node is, or it may have some problems in use.

Security combination mode UML class diagram

 

  As you can see from the above diagram, the biggest difference between secure and transparent composition patterns is that the Component base class no longer has all the subclasses of the method, so that Leaf does not have to implement some unnecessary methods, such as the branch node management method.

 

Advantages and disadvantages of combination mode

Advantage:

  1.The combination mode can clearly define the complex objects at different levels, representing all or part of the objects.

  2.When the user wants to ignore the difference between the combined object and the single object, the combination mode is adopted to improve the reusability of the software. So at this point, client code can use a composite structure or a single object uniformly.

  3.In a composite structure, it is easy to add new nodes or leaves. Because each subclass provides the ability to manage the builds it owns, there is no need to modify the original class at this point.

  4.It provides a flexible solution for tree structure. The tree with complex structure can be composed by recursive combination of leaves and branch nodes, but the complexity of tree management by client code will not increase.

Shortcomings:

  The design difficulty is increased. In designing, you need to abstract the structure of the whole tree and distinguish which should be leaves, but the problem is that not all nodes must be associated with leaves.

Code examples

  Imitate file system: There are two types of files in the file system, one is a directory (folder), the other is a normal file, directory can contain directories can also contain ordinary files, then ordinary files can not contain any type of files. The whole file system forms a tree structure. Since it is commonFiles and directories are all files, so we can abstract a file base class. In addition, normal files are nodes on a branch of the directory tree, as they can no longer contain any type of files. Next we will simulate the tree file system.

Transparent combination mode

1.Abstracts a base class of files and folders:

#ifndef COMPONENT_H_
#define COMPONENT_H_
#include <string>
class Component
{
public:
    virtual void add(Component *value) = 0;
    virtual void remove(Component *value) = 0;
    virtual Component* getChild(const int iIndex) = 0;
    virtual void displayOwnInfo(const int depth) const = 0;
    Component() = default;
    virtual ~Component() = default;
protected:
    std::string m_strName;
};
#endif

Component

2.General document class (Leaf)

#ifndef LEAF_H_
#define LEAF_H_
// This is a ordinary File class
#include "Component.h"
#include <iostream>
class Leaf : public Component
{
public:
    void add(Component* value) override;
    void remove(Component *value) override;
    Component* getChild(const int iIndex) override;
    void displayOwnInfo(const int depth) const override;
    Leaf(const std::string strName)
    {
    m_strName = strName;
    }
    ~Leaf() = default;
};
#endif

#include "Leaf.h"

void Leaf::add(Component* value)
{
    std::cout << "I am just a Leaf,There is nothing to do!" << std::endl;
}

void Leaf::remove(Component* value)
{
    std::cout << "I am just a Leaf.This is nothing to do!" << std::endl;
}

Component* Leaf::getChild(const int iIndex)
{
    std::cout << "I am just a Leaf.There is nothing to do!" << std::endl;
    return nullptr;
}

void Leaf::displayOwnInfo(const int depth) const
{
    std::string strOut('+',depth);
    std::cout << strOut << m_strName<<".I am a Leaf(Ordinary File)" <<std::endl;
}

Leaf

3.Directory class (Composite)

#ifndef COMPOSITE_H_
#define COMPOSITE_H_

#include "Component.h"
#include <vector>
#include <iostream>
class Composite:public Component
{
public:
    void add(Component *value);
    void remove(Component *value);
    Component* getChild(const int iIndex);
    void displayOwnInfo(const int depth) const;
    Composite(const std::string strName)
    {
    m_strName = strName;
    }
    ~Composite();
    Composite() = delete;
private:
    std::vector<Component*> m_vecComponent;
};
#endif

#include "Composite.h"

void Composite::add(Component *value)
{
    m_vecComponent.push_back(value);
}

void Composite::remove(Component *value)
{
    auto iter = m_vecComponent.begin();
    while(iter != m_vecComponent.end())
    {
    if(*iter == value)
        {
        if(nullptr != *iter)
        {
        delete value;
        value = nullptr;
        m_vecComponent.erase(iter);
        break;
        }
         }
         ++iter;
     }
}

Component* Composite::getChild(const int iIndex)
{
    if(iIndex <0 || iIndex >= m_vecComponent.size())
    return nullptr;
    return m_vecComponent[iIndex];
}

void Composite::displayOwnInfo(const int depth) const
{
    std::string strOut('+',depth);
    std::cout << strOut << m_strName << "I am a Dir!" << std::endl;
    for(auto it : m_vecComponent)
    {
    it->displayOwnInfo(depth+2);
    }
}

Composite::~Composite()
{
    for(auto it : m_vecComponent)
    {
    if(it != nullptr)
    {
        delete it;
        it = nullptr;
    }
    }
}

View Code

4.Client (client)

#include "Composite.h"
#include "Leaf.h"

using namespace std;

int main(int argc,char *argv[])
{
    //Create a Tree
    //Create a Root Node
    Composite *pRoot = new Composite("Root");
    //Create a Leaf
    Leaf *pIniFile = new Leaf("Ini.txt");
    pRoot->add(pIniFile);
    //Remove Leaf
    pRoot->remove(pIniFile);
    //Create a Branch
    Composite *p2Level = new Composite("2Level");
    Leaf *p2LevelLeaf1 = new Leaf("2LevelLeaf1");
    p2Level->add(p2LevelLeaf1);
    Composite *p3Level = new Composite("3Level");
    Leaf *p3LevelLeaf1 = new Leaf("3LevelLeaf1");
    p3Level->add(p3LevelLeaf1);
    p2Level->add(p3Level);
    pRoot->add(p2Level);
    
    
    pRoot->displayOwnInfo(1);
    return (1);
}

View Code

Security combination mode

  Insecurity in transparent composition means that there are more operations in leaf nodes than it should have – Methods for managing branch nodes, such as add, remove, getChild. If you want to make it safe, the simplest way is to remove these methods from the common base class.Late declarations and implementations are made in the Composite class so that branch nodes and leaf nodes are not insecure.

1.Abstracting the base class of ordinary files and directory files (Component in UML diagram)

#ifndef COMPONENT_H_
#define COMPONENT_H_
#include <string>
class Component
{
public:
    virtual void displayOwnInfo(const int depth) const = 0;
    Component() = default;
    virtual ~Component() = default;
protected:
    std::string m_strName;
};
#endif

Component

2.Generic file class (Leaf in UML class diagram)

#ifndef LEAF_H_
#define LEAF_H_
// This is a ordinary File class
#include "Component.h"
#include <iostream>
class Leaf : public Component
{
public:
    void displayOwnInfo(const int depth) const override;
    Leaf(const std::string strName)
    {
    m_strName = strName;
    }
    ~Leaf() = default;
};
#endif

#include "Leaf.h"


void Leaf::displayOwnInfo(const int depth) const
{
    std::string strOut(depth,'+');
    std::cout << strOut << m_strName<<".I am a Leaf(Ordinary File)" <<std::endl;
}

Leaf

3.Directory file class (Composite in UML class diagram)

#ifndef COMPOSITE_H_
#define COMPOSITE_H_

#include "Component.h"
#include <vector>
#include <iostream>
class Composite:public Component
{
public:
    void add(Component *value);
    void remove(Component *value);
    Component* getChild(const int iIndex);
    void displayOwnInfo(const int depth) const;
    Composite(const std::string strName)
    {
    m_strName = strName;
    }
    ~Composite();
    Composite() = delete;
private:
    std::vector<Component*> m_vecComponent;
};
#endif

#include "Composite.h"

void Composite::add(Component *value)
{
    m_vecComponent.push_back(value);
}

void Composite::remove(Component *value)
{
    auto iter = m_vecComponent.begin();
    while(iter != m_vecComponent.end())
    {
    if(*iter == value)
        {
        if(nullptr != *iter)
        {
        delete value;
        value = nullptr;
        m_vecComponent.erase(iter);
        break;
        }
         }
         ++iter;
     }
}

Component* Composite::getChild(const int iIndex)
{
    if(iIndex <0 || iIndex >= m_vecComponent.size())
    return nullptr;
    return m_vecComponent[iIndex];
}

void Composite::displayOwnInfo(const int depth) const
{
    std::string strOut(depth,'+');
    std::cout << strOut << m_strName << "I am a Dir!" << std::endl;
    for(auto it : m_vecComponent)
    {
    it->displayOwnInfo(depth+2);
    }
}

Composite::~Composite()
{
    for(auto it : m_vecComponent)
    {
    if(it != nullptr)
    {
        delete it;
        it = nullptr;
    }
    }
}

Composite

4.mainFunction (Client in UML class diagram)

#include "Composite.h"
#include "Leaf.h"

using namespace std;

int main(int argc,char *argv[])
{
    //Create a Tree
    //Create a Root Node
    Composite *pRoot = new Composite("Root");
    //Create a Leaf
    Leaf *pIniFile = new Leaf("Ini.txt");
    pRoot->add(pIniFile);
    //Remove Leaf
    pRoot->remove(pIniFile);
    //Create a Branch
    Composite *p2Level = new Composite("2Level");
    Leaf *p2LevelLeaf1 = new Leaf("2LevelLeaf1");
    p2Level->add(p2LevelLeaf1);
    Composite *p3Level = new Composite("3Level");
    Leaf *p3LevelLeaf1 = new Leaf("3LevelLeaf1");
    p3Level->add(p3LevelLeaf1);
    p2Level->add(p3Level);
    pRoot->add(p2Level);
    
    
    pRoot->displayOwnInfo(1);
    return (1);
}

Client

 

Leave a Reply

Your email address will not be published. Required fields are marked *