zoukankan      html  css  js  c++  java
  • (原创)composite模式和bridge模式是天生的好朋友

      composite模式的意图是:将对象组合成树形结构以表示“部分-整体”的层次结构。composite使得用户对单个对象和组合对象的使用具有一致性。它的类图如下:

      composite模式的实现分为透明的composite模式和安全的composite模式,二者的差别是添加、删除和获取子节点的行为放到基类还是放到复合节点类中。透明的则放到基类中,但是这些行为对于不可再分的叶子节点来说是无意义的,对于存在子节点的复合节点才有意义。但是透明的组合模式具有更好的一致性和可读性,一般都建议用透明的组合模式,在基类中提供这些行为的空的虚方法,只在复合节点中重写这些虚方法。

      透明的组合模式的简单实现如下:

    #include <vector>
    #include <iostream>
    #include <memory>
    using namespace std;
    struct Component
    {
        Component()
        {
        }
    
        virtual ~Component()
        {
        }
    
        virtual void Add(std::shared_ptr<Component>)
        {
    
        }
    
        virtual void Operate()
        {
    
        }
    };
    
    struct Leaf : Component
    {
        void Operate() override
        {
            cout << "Leaf" << endl;
        }
    };
    
    struct OtherLeaf : Component
    {
        void Operate() override
        {
            cout << "OtherLeaf" << endl;
        }
    };
    
    struct Composite : Component
    {
        void Add(std::shared_ptr<Component> child) override
        {
            m_children.push_back(child);
        }
    
        void Operate() override
        {
            cout << "Composite" << endl;
    
            for (auto child : m_children)
            {
                child->Operate();
            }
        }
    
    private:
        vector<std::shared_ptr<Component>> m_children;
    };
    View Code

      bridge模式的意图是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它的类图如下:

      桥接模式的实现比较简单,桥的两边是两个独立的继承体系,桥的左边是抽象部分的继承体系,桥的右边是实现部分的继承体系,这两个继承体系之前通过一座桥来关联,当抽象部分需要实现部分的某种实现时,在外面指定具体实现类即可。桥接模式充分的解耦了抽象与实现,使得他们都可以独立的变化,增强了灵活性和可扩展性。桥接模式的实现中,设置某个实现时,有两种方法,一种是由外面选择是哪种实现,一种由派生类选择时哪种实现,由外面选择的方式降低了两边的耦合性,但是需要知道更多的细节,当扩展新的实现时不得不修改,而派生类自己选择则增强了耦合性,即抽象的派生类需要知道实现的派生类,但是它能适应扩展,扩展一个新抽象时,不用修改代码,只在派生类自己选择就行了,封装了变化。至于如何选择看自己的选择了,我个人觉得派生类中选择更好,可以封装变化。

      桥接模式的简单实现如下:

    #include <iostream>
    #include <memory>
    using namespace std;
    
    struct Implementation
    {
        virtual void Operate() = 0;
        ~Implementation(){}
    };
    
    struct DerivedImplement1 : Implementation
    {
        void Operate() override
        {
            cout << "do DerivedImplement1" << endl;
        }
    };
    
    struct DerivedImplement2 : Implementation
    {
        void Operate() override
        {
            cout << "do DerivedImplement2" << endl;
        }
    };
    
    
    struct Abstraction
    {
        void SetImplementation(std::shared_ptr<Implementation> impl)
        {
            m_impl = impl;
        }
    
        virtual void Operate()
        {
            if (m_impl!=nullptr)
                m_impl->Operate();
        }
    
        ~Abstraction(){}
    
    protected:
        std::shared_ptr<Implementation> m_impl;
    };
    
    
    struct DerivedAbstraction1 : Abstraction
    {
    
    };
    
    struct DerivedAbstraction2 : Abstraction
    {
    
    };
    
    void TestBridge()
    {
        std::shared_ptr<Abstraction> abstract1 = std::make_shared<DerivedAbstraction1>();
        std::shared_ptr<Abstraction> abstract2 = std::make_shared<DerivedAbstraction2>();
    
        std::shared_ptr<Implementation> impl1 = std::make_shared<DerivedImplement1>();
        std::shared_ptr<Implementation> impl2 = std::make_shared<DerivedImplement2>();
        abstract1->SetImplementation(impl2);
        abstract2->SetImplementation(impl1);
        abstract1->Operate();
        abstract2->Operate();
    }
    View Code

      介绍了两个的模式的实现之后再来看看为什么他们是天生的好朋友,compostite主要封装了对象结构的变化,它可能有很多叶子节点或者复合嵌套节点,我们可以以统一的方式去访问这些对象,这很方便。然而当这些对象具有一些不同的行为的时候,事情就变得有趣了,因为节点类型不同对应的行为也不同,这个行为是属于另外一个继承体系,如何将两个继承体系绑定起来,为每个composite模式中节点指定一个行为呢?如果通过工厂来选择的话,则工厂需要根据节点类型来选择对应的行为,这能解决问题但是当节点类型增加时就要修改工厂类,无法做到“开放封闭”。解决这个问题的关键是如何满足两个继承体系独立的变化,这时候通过桥接模式就能很好的解决这个问题。composite属于“桥”左边的抽象部分的继承体系,其行为对应“桥”右边的继承体系,通过指定抽象部分的某个具体派生类对应的某个具体实现就能实现,就能实现抽象和实现的解耦了。

      将组合模式和桥接模式结合起来的类图如下:

      具体实现如下:

    #include <vector>
    #include <iostream>
    #include <memory>
    using namespace std;
    #include "Bridge.hpp"
    struct Component
    {
        Component()
        {
        }
    
        virtual ~Component()
        {
        }
    
        virtual void Add(std::shared_ptr<Component> child)
        {
    
        }
    
        virtual void Operate()
        {
            if (m_impl)
                m_impl->Operate();
        }
    
        virtual void SetImplementation()
        {
            
        }
    
    protected:
        std::shared_ptr<Implementation> m_impl;
    };
    
    struct Leaf : Component
    {
        void Operate() override
        {
            cout << "Leaf" << endl;
            Component::Operate();
        }
    
        void SetImplementation() override
        {
            m_impl = std::make_shared<DerivedImplement1>();
            
        }
    };
    
    struct OtherLeaf : Component
    {
        void Operate() override
        {
            cout << "OtherLeaf" << endl;
            Component::Operate();
        }
    
        void SetImplementation() override
        {
            m_impl = std::make_shared<DerivedImplement2>();
        }
    };
    
    struct Composite : Component
    {
        void Add(std::shared_ptr<Component> child) override
        {
            m_children.push_back(child);
        }
    
        void Operate() override
        {
            cout << "Composite" << endl;
    
            for (auto child : m_children)
            {
                child->Operate();
            }
        }
    
        void SetImplementation() override
        {
            for (auto child : m_children)
            {
                child->SetImplementation();
            }
        }
    
    private:
        vector<std::shared_ptr<Component>> m_children;
    };
    
    void TestComposite()
    {
        std::shared_ptr<Component> root = std::make_shared<Composite>();
    
        std::shared_ptr<Component> leaf = std::make_shared<Leaf>();
        std::shared_ptr<Component> otherLeaf = std::make_shared<OtherLeaf>();
        root->Add(leaf);
        root->Add(otherLeaf);
        root->SetImplementation();
        root->Operate();
    }
    View Code

      可以看到composite模式代表了抽象部分的继承体系,如果要给这个变化的继承体系增加行为,则需要对应一个实现部分的继承体系,而桥接模式刚好就可以将连个继承体系通过一座“桥”关联起来,让这两个继承体系独立变化,二者结合起来非常自然,所以说他们天生就是一对好朋友。

    如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。

    c++11 boost技术交流群:296561497,欢迎大家来交流技术。

  • 相关阅读:
    《柯尔特思维教程》-第6章(行动)- 第7节:解决方案
    《柯尔特思维教程》-第6章(行动)- 第6节:输入
    《柯尔特思维教程》-第6章(行动)- 第5节:思维的目的
    《柯尔特思维教程》-第6章(行动)- 第4节:TEC
    《柯尔特思维教程》-第6章(行动)- 第3节:缩小
    《柯尔特思维教程》-第6章(行动)- 第2节:扩展
    《柯尔特思维教程》-第6章(行动)- 第1节:目标
    《柯尔特思维教程》-第5章(信息和情感)- 第10节:SF&CF:简化和澄清
    Oracle-日常运维-删除临时文件回收空间
    OGG-Oracle 集成模式抽取进程,REGISTER DATABASE都做了什么?
  • 原文地址:https://www.cnblogs.com/qicosmos/p/3658750.html
Copyright © 2011-2022 走看看