(原创)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;
};
bridge模式的意图是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它的类图如下:

桥接模式的实现比较简单,桥的两边是两个独立的继承体系,桥的左边是抽象部分的继承体系,桥的右边是实现部分的继承体系,这两个继承体系之前通过一座桥来关联,当抽象部分需要实现部分的某种实现时,在外面指定具体实现类即可。桥接模式充分的解耦了抽象与实现,使得他们都可以独立的变化,增强了灵活性和可扩展性。桥接模式的实现中,设置某个实现时,有两种方法,一种是由外面选择是哪种实现,一种由派生类选择时哪种实现,由外面选择的方式降低了两边的耦合性,但是需要知道更多的细节,当扩展新的实现时不得不修改,而派生类自己选择则增强了耦合性,即抽象的派生类需要知道实现的派生类,但是它能适应扩展,扩展一个新抽象时,不用修改代码,只在派生类自己选择就行了,封装了变化。至于如何选择看自己的选择了,我个人觉得派生类中选择更好,可以封装变化。
桥接模式的简单实现如下:
#include <iostream>
#include <memory>
using namespace std; struct Implementation
{
virtual void Operate() = ;
~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();
}
介绍了两个的模式的实现之后再来看看为什么他们是天生的好朋友,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();
}
可以看到composite模式代表了抽象部分的继承体系,如果要给这个变化的继承体系增加行为,则需要对应一个实现部分的继承体系,而桥接模式刚好就可以将连个继承体系通过一座“桥”关联起来,让这两个继承体系独立变化,二者结合起来非常自然,所以说他们天生就是一对好朋友。
如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。
c++11 boost技术交流群:296561497,欢迎大家来交流技术。
(原创)composite模式和bridge模式是天生的好朋友的更多相关文章
- Java设计模式(6)桥模式(Bridge模式)
Bridge定义:将抽象和行为划分开来,各自独立,但能动态的结合. 为什么使用桥模式 通常,当一个抽象类或接口有多个具体实现(concrete subclass),这些concrete之间关系可能有以 ...
- 设计模式——桥接模式(Bridge模式)
基本介绍 桥接模式(Bridge模式):将实现与抽象放在两个不同的类层次中,使两层次可以独立改变 是一种结构型设计模式 说白了就是有多个维度的变化,这样的组合关系如果按照传统的方式会导致类爆炸,所以需 ...
- Abstract Server模式,Adapter模式和Bridge模式
简易的台灯 Abstract Server模式 谁拥有接口. 接口属于它的客户,而不是它的派生类. 接口和客户之间的逻辑关系,强于接口和其派生类的逻辑关系. 逻辑关系和实体关系的强度是不一致的.在实体 ...
- 设计模式之桥接模式(Bridge模式)
我想大家小时候都有用蜡笔画画的经历吧.红红绿绿的蜡笔一大盒,根据想象描绘出格式图样.而毛笔下的国画更是工笔写意,各展风采.而今天我们的故事从蜡笔与毛笔说起. 设想要绘制一幅图画,蓝天.白云.绿树.小鸟 ...
- 桥接模式(Bridge模式)
桥接模式的定义与特点 桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化.它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度.通过上面的讲解,我们能很好 ...
- PHP设计模式(八)桥接模式(Bridge For PHP)
一.概述 桥接模式:将两个原本不相关的类结合在一起,然后利用两个类中的方法和属性,输出一份新的结果. 二.案例 1.模拟毛笔(转) 需求:现在需要准备三种粗细(大中小),并且有五种颜色的比 如果使用蜡 ...
- Android中Adapter和Bridge模式理解和应用
一 Adapter模式 意图: 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以在一起工作. 适用性: 使用一个已存在的类,而它的接口 ...
- Java设计模式(22)命令模式(Command模式)
Command模式是最让我疑惑的一个模式,我在阅读了很多代码后,才感觉隐约掌握其大概原理,我认为理解设计模式最主要是掌握起原理构造,这样才对自己实际编程有指导作用.Command模式实际上不是个很具体 ...
- Java设计模式(19)状态模式(State模式)
State的定义:不同的状态,不同的行为:或者说,每个状态有着相应的行为. 何时使用状态模式 State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If else ...
随机推荐
- 【onethink搬家】win环境移植linux环境,注意事项
onethink 搬家注意事项: 修改目录/文件归属和权限,Runtime目录要有可写权限. 若数据库有变动,则需要更改数据库连接参数.在Application/Common/Conf/config. ...
- <转>lua解释执行脚本流程
本文转自:http://www.cnblogs.com/zxh1210603696/p/4458473.html #include "lua.hpp" #include <i ...
- hihocoder216周:贪心或二分
题目链接 有N条线段,要切K刀,使得最长的线段尽量短.在最佳切割的条件下,切完之后最长的那根绳子是多长. 方法一:贪心 每次切的那一刀必然是最长的那条线段,用优先队列,每次往最长的那条线段上切一刀 方 ...
- Python实现鸢尾花数据集分类问题——基于skearn的SVM
Python实现鸢尾花数据集分类问题——基于skearn的SVM 代码如下: # !/usr/bin/env python # encoding: utf-8 __author__ = 'Xiaoli ...
- LPDMvvmKit 系列之 UITableView 的改造
阅读本文需要对ReactiveCocoa足够了解,也可以参阅图解ReactiveCocoa基本函数(http://www.jianshu.com/p/38d39923ee81) Cocoa Touch ...
- c# 4.0 - how to i SMTP with c# 4/.NET 4 to port 465/SSL (...
first, i've discovered through trial and error that c# 4/.NET 4 has some serious limitations which a ...
- 【Oracle】浅析Oracle中的事务
1. 什么是事务 在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么都成功执行,完成整个工作单元操作,要么一个也不 ...
- Spring 注解 hibernate 实体方法 <property name="packagesToScan" value="com.sise.domain"/>
<property name="annotatedClasses"> <list> <value>com.sise.domain.Admin&l ...
- 【Linux】数据流重导向(前篇)
数据流重导向 (redirect) 由字面上的意思来看,好像就是将『数据给他传导到其他地方去』的样子? 没错-数据流重导向就是将某个命令运行后应该要出现在屏幕上的数据, 给他传输到其他的地方,例如文件 ...
- 懒得说IE6了,写个js插件不能写注释,原因如下
变态的ie6将注释当代码解释 ie6宽松的安全环境对于开发人员是开心的,比如运行速度快(对于ie7/8/9).支持部份文件操作等.但也有很多烦忧,比如对数组.对象的检测比较机械,这还不算什么,这两天让 ...