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

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

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

  1. #include <vector>
  2. #include <iostream>
  3. #include <memory>
  4. using namespace std;
  5. struct Component
  6. {
  7. Component()
  8. {
  9. }
  10.  
  11. virtual ~Component()
  12. {
  13. }
  14.  
  15. virtual void Add(std::shared_ptr<Component>)
  16. {
  17.  
  18. }
  19.  
  20. virtual void Operate()
  21. {
  22.  
  23. }
  24. };
  25.  
  26. struct Leaf : Component
  27. {
  28. void Operate() override
  29. {
  30. cout << "Leaf" << endl;
  31. }
  32. };
  33.  
  34. struct OtherLeaf : Component
  35. {
  36. void Operate() override
  37. {
  38. cout << "OtherLeaf" << endl;
  39. }
  40. };
  41.  
  42. struct Composite : Component
  43. {
  44. void Add(std::shared_ptr<Component> child) override
  45. {
  46. m_children.push_back(child);
  47. }
  48.  
  49. void Operate() override
  50. {
  51. cout << "Composite" << endl;
  52.  
  53. for (auto child : m_children)
  54. {
  55. child->Operate();
  56. }
  57. }
  58.  
  59. private:
  60. vector<std::shared_ptr<Component>> m_children;
  61. };

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

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

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

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4.  
  5. struct Implementation
  6. {
  7. virtual void Operate() = ;
  8. ~Implementation(){}
  9. };
  10.  
  11. struct DerivedImplement1 : Implementation
  12. {
  13. void Operate() override
  14. {
  15. cout << "do DerivedImplement1" << endl;
  16. }
  17. };
  18.  
  19. struct DerivedImplement2 : Implementation
  20. {
  21. void Operate() override
  22. {
  23. cout << "do DerivedImplement2" << endl;
  24. }
  25. };
  26.  
  27. struct Abstraction
  28. {
  29. void SetImplementation(std::shared_ptr<Implementation> impl)
  30. {
  31. m_impl = impl;
  32. }
  33.  
  34. virtual void Operate()
  35. {
  36. if (m_impl!=nullptr)
  37. m_impl->Operate();
  38. }
  39.  
  40. ~Abstraction(){}
  41.  
  42. protected:
  43. std::shared_ptr<Implementation> m_impl;
  44. };
  45.  
  46. struct DerivedAbstraction1 : Abstraction
  47. {
  48.  
  49. };
  50.  
  51. struct DerivedAbstraction2 : Abstraction
  52. {
  53.  
  54. };
  55.  
  56. void TestBridge()
  57. {
  58. std::shared_ptr<Abstraction> abstract1 = std::make_shared<DerivedAbstraction1>();
  59. std::shared_ptr<Abstraction> abstract2 = std::make_shared<DerivedAbstraction2>();
  60.  
  61. std::shared_ptr<Implementation> impl1 = std::make_shared<DerivedImplement1>();
  62. std::shared_ptr<Implementation> impl2 = std::make_shared<DerivedImplement2>();
  63. abstract1->SetImplementation(impl2);
  64. abstract2->SetImplementation(impl1);
  65. abstract1->Operate();
  66. abstract2->Operate();
  67. }

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

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

  具体实现如下:

  1. #include <vector>
  2. #include <iostream>
  3. #include <memory>
  4. using namespace std;
  5. #include "Bridge.hpp"
  6. struct Component
  7. {
  8. Component()
  9. {
  10. }
  11.  
  12. virtual ~Component()
  13. {
  14. }
  15.  
  16. virtual void Add(std::shared_ptr<Component> child)
  17. {
  18.  
  19. }
  20.  
  21. virtual void Operate()
  22. {
  23. if (m_impl)
  24. m_impl->Operate();
  25. }
  26.  
  27. virtual void SetImplementation()
  28. {
  29.  
  30. }
  31.  
  32. protected:
  33. std::shared_ptr<Implementation> m_impl;
  34. };
  35.  
  36. struct Leaf : Component
  37. {
  38. void Operate() override
  39. {
  40. cout << "Leaf" << endl;
  41. Component::Operate();
  42. }
  43.  
  44. void SetImplementation() override
  45. {
  46. m_impl = std::make_shared<DerivedImplement1>();
  47.  
  48. }
  49. };
  50.  
  51. struct OtherLeaf : Component
  52. {
  53. void Operate() override
  54. {
  55. cout << "OtherLeaf" << endl;
  56. Component::Operate();
  57. }
  58.  
  59. void SetImplementation() override
  60. {
  61. m_impl = std::make_shared<DerivedImplement2>();
  62. }
  63. };
  64.  
  65. struct Composite : Component
  66. {
  67. void Add(std::shared_ptr<Component> child) override
  68. {
  69. m_children.push_back(child);
  70. }
  71.  
  72. void Operate() override
  73. {
  74. cout << "Composite" << endl;
  75.  
  76. for (auto child : m_children)
  77. {
  78. child->Operate();
  79. }
  80. }
  81.  
  82. void SetImplementation() override
  83. {
  84. for (auto child : m_children)
  85. {
  86. child->SetImplementation();
  87. }
  88. }
  89.  
  90. private:
  91. vector<std::shared_ptr<Component>> m_children;
  92. };
  93.  
  94. void TestComposite()
  95. {
  96. std::shared_ptr<Component> root = std::make_shared<Composite>();
  97.  
  98. std::shared_ptr<Component> leaf = std::make_shared<Leaf>();
  99. std::shared_ptr<Component> otherLeaf = std::make_shared<OtherLeaf>();
  100. root->Add(leaf);
  101. root->Add(otherLeaf);
  102. root->SetImplementation();
  103. root->Operate();
  104. }

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

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

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

(原创)composite模式和bridge模式是天生的好朋友的更多相关文章

  1. Java设计模式(6)桥模式(Bridge模式)

    Bridge定义:将抽象和行为划分开来,各自独立,但能动态的结合. 为什么使用桥模式 通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以 ...

  2. 设计模式——桥接模式(Bridge模式)

    基本介绍 桥接模式(Bridge模式):将实现与抽象放在两个不同的类层次中,使两层次可以独立改变 是一种结构型设计模式 说白了就是有多个维度的变化,这样的组合关系如果按照传统的方式会导致类爆炸,所以需 ...

  3. Abstract Server模式,Adapter模式和Bridge模式

    简易的台灯 Abstract Server模式 谁拥有接口. 接口属于它的客户,而不是它的派生类. 接口和客户之间的逻辑关系,强于接口和其派生类的逻辑关系. 逻辑关系和实体关系的强度是不一致的.在实体 ...

  4. 设计模式之桥接模式(Bridge模式)

    我想大家小时候都有用蜡笔画画的经历吧.红红绿绿的蜡笔一大盒,根据想象描绘出格式图样.而毛笔下的国画更是工笔写意,各展风采.而今天我们的故事从蜡笔与毛笔说起. 设想要绘制一幅图画,蓝天.白云.绿树.小鸟 ...

  5. 桥接模式(Bridge模式)

    桥接模式的定义与特点 桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化.它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度.通过上面的讲解,我们能很好 ...

  6. PHP设计模式(八)桥接模式(Bridge For PHP)

    一.概述 桥接模式:将两个原本不相关的类结合在一起,然后利用两个类中的方法和属性,输出一份新的结果. 二.案例 1.模拟毛笔(转) 需求:现在需要准备三种粗细(大中小),并且有五种颜色的比 如果使用蜡 ...

  7. Android中Adapter和Bridge模式理解和应用

    一 Adapter模式 意图: 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以在一起工作. 适用性: 使用一个已存在的类,而它的接口 ...

  8. Java设计模式(22)命令模式(Command模式)

    Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体 ...

  9. Java设计模式(19)状态模式(State模式)

    State的定义:不同的状态,不同的行为:或者说,每个状态有着相应的行为. 何时使用状态模式 State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If else ...

随机推荐

  1. 实现两个Mysql数据库同步

    一.     概述  MySQL从3.23.15版本以后提供数据库复制(replication)功能,利用该功能可以实现两个数据库同步.主从模式.互相备份模式的功能.本文档主要阐述了如何在linux系 ...

  2. ASP.NET MVC3-第02节-添加一个Controller (C#)

    前言 ---------------------------- 第01节[翻译]01-ASP.NET MVC 3介绍 ---------------------------- MVC是“model-v ...

  3. 使用Thrift让Python为Java提供服务

    Thrift是基于TCP的,谷歌的GRPC是基于HTTP的.Thrift和GRPC都是比直接写个web接口进行调用更完美的方式,最明显的一点就是:我们可以定义结构体,避免了手动解析的过程. 但是,在将 ...

  4. 简单的Java串口通讯应答示例

    java串口通讯第一次使用,找的资料都比较麻烦,一时没有理出头绪,自己在示例的基础上整理了一个简单的应答示例,比较简陋,但演示了java串口通讯的基本过程. package com.garfield. ...

  5. iOS之ProtocolBuffer搭建

    一.环境安装:pb编译器的安装 1.从https://github.com/google/protobuf/releases下载protocolBuffer对应版本编译器包,比如目前的对应的objc最 ...

  6. [转] mysql --prompt介绍

    mysql --prompt修改命令行链接mysql时的提示符,shell脚本示例如下 #!/bin/bash case $1 in crm) cmd='mysql -h192.168.1.2 -ur ...

  7. java中enum的应用

    package com.demo; public enum TestEnum { A("hello"), B("world"); private String ...

  8. C/C++函数指针(typedef简化定义)

    学习要点:        1,函数地址的一般定义和typedef简化定义;        2,函数地址的获取;        3,A函数地址作为B函数参数的传递;    函数存放在内存的代码区域内,它 ...

  9. 关于ps cs5的一些问题

    一.photoshop cs5 默认在窗口中浮动方法 1.打开“编辑>首选项>界面”在“面板和文档”里把“以选项卡方式打开图像”的勾选去掉 2.点击菜单栏“窗口>排列>使所有内 ...

  10. php超时时间说明

    一,http请求超时时间 可能出现的场景: 1,curl进程运行了一个世纪还木结束,curl的时候设置了超时时间 --connect-timeout 1000 2,operation timed ou ...