zoukankan      html  css  js  c++  java
  • 设计模式之组合模式

    2018-09-20 16:12:07

    组合模式(Composite)

      组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象(即叶子构件)和组合对象(即组合构件)的使用具有一致性。(例如,你可以在word里对单个字和一行字采用同样的操作)注意,这里说的树就是一颗树,没有任何的限制,它可以是任何形状的。这棵树它是靠对象之间的组合关系构建起来,而非数据结构意义上的树。

    何时使用组合模式

      当你发现需求中是体现部分整体层次的结构(树状结构)时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑组合模式了。

    组合模式UML类图

    组合模式根据实现的不同可以分为两种:透明方式组合模式、安全方式组合模式

    透明方式组合模式UML类图:

       在透明组合模式中,Component是应用了组合模式的所有构件的基类,它提供了整个模式结构中所有子类的公共方法,另外提供了用于管理以及访问子构件的方法(例如Add、Remove、GetChild)

      Leaf在这个结构中表示叶子结点,就像数据结构中的树一样,叶子结点不能有子节点。所以很明显的问题是,叶子结点实现用于管理子构件的方法:Add、Remove、GetChild毫无意义。这个就是透明组合模式存在的问题。

      Composite:在它的内部有一个包含Component指针对象的列表,因为在整个模式中,Composite表示的是一个分支结点,分支结点下又可能有数量不定的分支结点,这个列表的作用就是保存分支结点的子节点用的。在Composite中实现了用于管理子节点的方法:Add、Remove、GetChild。

      透明组合模式的好处在于,对client来说屏蔽了叶子节点和分支结点的差异。但client必须要明确的知道哪个是叶子结点,否则在使用上可能会出现一些问题。

    安全组合模式UML类图

      从上图可以看出安全组合模式和透明组合模式最大的差别就是Component基类不再具有所有子类的方法,这样Leaf就不必实现一些不必要的方法了,例如对分支结点的管理方法。

    组合模式的优缺点

    优点:

      1.组合模式可以清楚的定义分层次的复杂对象,表示对象的全部或部分层次。

      2.当用户希望忽略组合对象和单个对象的不同时,采用组合模式,提高了软件的可复用性。因此此时,client代码可以一致的使用组合结构或者其中的单个对象。

      3.在组合结构中,添加新的节点或者叶子是一件很容易的事情。因为每个子类都提供了对它所拥有的构建进行管理的能力,所以此时无需对原有的类进行修改。

      4.为树形结构提供了一种灵活的解决方案,通过递归组合叶子和分支结点可以组合出结构复杂的树,但同时client代码对树的管理的复杂度不会提高。

    缺点:

      增大了设计难度。在进行设计时你需要先抽象出整个树的结构,区分清楚哪些应该是叶子,但问题在于不是所有的结点都必须会和叶子有关联。

    代码示例

      模仿文件系统:文件系统中有两类文件,一种是目录(文件夹)、另外一种就是普通文件,目录下可以包含目录也可以包含普通文件,当时普通文件下是不能包含任何类型的文件的。整个文件系统构成了一个树形结构。既然普通文件和目录都是文件,那么我们可以抽象出一个文件基类。另外,由普通文件下不能再包含任何类型文件可知,普通文件是目录树一个分支上的节点。接下来我们来模拟一下这个树形的文件系统。

    透明组合模式

    1.抽象出一个文件和文件夹的基类:

    #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.普通文件类 (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.目录类(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)

    #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

    安全组合模式

      透明组合模式中的不安全,其实就是说叶子结点中多了它不该有的操作——对分支结点进行管理的方法,例如add、remove、getChild。要想使它安全,那么最简单的办法就是把这些方法从公共基类里剔除,延迟到Composite类里去声明和实现,这样分支结点和叶子结点就不会有不安全的因素了。

    1.抽象出普通文件和目录文件的基类(UML图中的Component)

    #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.普通文件类(UML类图中的Leaf)

    #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.目录文件类(UML类图中的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;
        }
        }
    }
    Composite

    4.main函数(UML类图中的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);
    }
    Client
  • 相关阅读:
    JVM内存分配及GC流程
    打印手机当前界面(位于栈顶)的activity
    AIDL通信过程中设置死亡代理
    最短路径&次短路径算法
    DEX、ODEX、OAT文件&Dalvik和ART虚拟机
    主线程中有多个handler的情况
    GB GBRT XgBoost
    logistic回归为什么要使用sigmoid函数
    十道海量数据处理面试题与十个方法大总结
    常见数据结构和算法题
  • 原文地址:https://www.cnblogs.com/ToBeExpert/p/9682277.html
Copyright © 2011-2022 走看看