桥接模式

先说说桥接模式的定义:将抽象化(Abstraction)与实现化(Implementation)分离,使得二者可以独立地变化。

桥接模式号称设计模式中最难理解的模式之一,关键就是这个抽象和实现的分离非常让人奇怪,大部分人刚看到这个定义的时候都会认为实现就是继承自抽象,那怎么可能将他们分离呢。

这里引用《大话设计模式》里面的那个例子。这个例子中,每次添加一个新的手机品牌,则必须要添加相应的通讯录和游戏,而每次要给每个手机添加新功能,则所有的手机品牌下都必须继承一个新的类,这样工作量就大了,而且可能通讯录和游戏的实现方法是一样的,这就有很多重复代码。看到这里可能已经看到了端倪了,虽然这个最顶层的抽象手机品牌一般是固定不变的,但是下面的各个继承类手机品牌M和手机品牌N却是时常会发生变化的。而只要手机品牌M和手机品牌N发生变化,它下面的继承类也要发生变化,这样极大的增加了代码的耦合性,加入通讯录和游戏下面还继续继承有类的话,那耦合性就更强了,改起来基本就是噩梦了。

其实也可以这样看,虽然手机品牌M和手机品牌N这两个类是有一部分抽象,但是还没有达到完全的抽象,还是会发生变化的。

所以,其实定义里说的实现是指的最下层的那些具体实现,抽象是指的他的父类或者更上层的父类,而要将抽象和实现分离,就是分离这个抽象和实现。说的通俗点,就是不要继承的太多了,最好是就继承一层。(我自己的理解)所以才有了合成/聚合复用原则。

合成/聚合复用原则:尽量使用合成/聚合,尽量不要使用类继承。我对这句话的理解就是,不要继承太多了,如果需要太多继承,可以考虑改为合成/聚合。

下面可以看看桥接模式的具体类图了。桥接模式就将实现与抽象分离开来,使得RefinedAbstraction依赖于抽象的实现,这样实现了依赖倒转原则,而不管左边的抽象如何变化,只要实现方法不变,右边的具体实现就不需要修改,而右边的具体实现方法发生变化,只要接口不变,左边的抽象也不需要修改。

说起来,其实桥接模式倒是与抽象工厂模式有点像,可以回忆一下抽象工厂模式,抽象工厂模式也是解决多种因素变化的一种方式,抽象工厂模式中,产品的种类和产品的具体实现都会发生变化,于是将产品的种类抽象出来,将具体的实现隔离开来。

最新体会:有一种情况,你事先定义了Abstction类和RefinedAbstraction类,你的代码中直接使用的是RefinedAbstraction类,刚开始RefinedAbstraction是够用的。但后来你希望operation()能在不同的情况下有不同的实现,这时候原有的结构就不够用了,你不可能重新继承一个类,那样所有的地方都必须修改,可以考虑的做法就是继承RefinedAbstraction类,这样的改动就比较少,但这样不是最好的。最好的应该是使用上面的桥接模式,将实现分离出来,这样所有的地方都不需要修改,只要添加它的实现就可以了。

常用的场景

1.当一个对象有多个变化因素的时候,考虑依赖于抽象的实现,而不是具体的实现。如上面例子中手机品牌有2种变化因素,一个是品牌,一个是功能。

2.当多个变化因素在多个对象间共享时,考虑将这部分变化的部分抽象出来再聚合/合成进来,如上面例子中的通讯录和游戏,其实是可以共享的。

3.当我们考虑一个对象的多个变化因素可以动态变化的时候,考虑使用桥接模式,如上面例子中的手机品牌是变化的,手机的功能也是变化的,所以将他们分离出来,独立的变化。

优点

1.将实现抽离出来,再实现抽象,使得对象的具体实现依赖于抽象,满足了依赖倒转原则。

2.将可以共享的变化部分,抽离出来,减少了代码的重复信息。

3.对象的具体实现可以更加灵活,可以满足多个因素变化的要求。

缺点

1.客户必须知道选择哪一种类型的实现。

C++实现代码

 #ifndef _ABSTRACTION_H_
#define _ABSTRACTION_H_ #include "AbstractionImplement.h" class Abstraction
{
public:
Abstraction();
virtual ~Abstraction(); virtual void operation() = ; }; class DefinedAbstraction: public Abstraction
{
public:
DefinedAbstraction(AbstractionImplement* absImp);
~DefinedAbstraction(); void operation(); private:
AbstractionImplement* absImp;
}; #endif
 #include "Abstraction.h"

 Abstraction::Abstraction()
{ } Abstraction::~Abstraction()
{ } DefinedAbstraction::DefinedAbstraction(AbstractionImplement* absImp)
{
this->absImp = absImp;
} DefinedAbstraction::~DefinedAbstraction()
{ } void DefinedAbstraction::operation()
{
absImp->operation();
}
 #ifndef _ABSTRACTIONIMPLEMENT_H_
#define _ABSTRACTIONIMPLEMENT_H_ class AbstractionImplement
{
public:
AbstractionImplement();
virtual ~AbstractionImplement(); virtual void operation() = ;
}; class ConcreteAbstractionImplement1:public AbstractionImplement
{
public:
ConcreteAbstractionImplement1();
~ConcreteAbstractionImplement1(); void operation();
}; class ConcreteAbstractionImplement2:public AbstractionImplement
{
public:
ConcreteAbstractionImplement2();
~ConcreteAbstractionImplement2(); void operation();
}; #endif
 #include "AbstractionImplement.h"
#include <stdio.h> AbstractionImplement::AbstractionImplement()
{ } AbstractionImplement::~AbstractionImplement()
{ } ConcreteAbstractionImplement1::ConcreteAbstractionImplement1()
{ } ConcreteAbstractionImplement1::~ConcreteAbstractionImplement1()
{ } void ConcreteAbstractionImplement1::operation()
{
fprintf(stderr, "ConcreteAbstractionImplement1\n" );
} ConcreteAbstractionImplement2::ConcreteAbstractionImplement2()
{ } ConcreteAbstractionImplement2::~ConcreteAbstractionImplement2()
{ } void ConcreteAbstractionImplement2::operation()
{
fprintf(stderr, "ConcreteAbstractionImplement2\n" );
}
 #include "Abstraction.h"

 int main()
{
AbstractionImplement* absImp1 = new ConcreteAbstractionImplement1();
Abstraction* abs1 = new DefinedAbstraction(absImp1); abs1->operation(); AbstractionImplement* absImp2 = new ConcreteAbstractionImplement2();
Abstraction* abs2 = new DefinedAbstraction(absImp2); abs2->operation();
return ;
}
 g++ -o client client.cpp Abstraction.cpp AbstractionImplement.cpp

运行结果

桥接模式及C++实现的更多相关文章

  1. BridgePattern(桥接模式)

    /** * 桥接模式 * @author TMAC-J * 应用于多维度方案 * 用组合的形式代替继承 * 符合单一职责原则 * 一个类只有一个引起他变化的原因 * 增加程序灵活性 */ public ...

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

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

  3. 设计模式(八)桥接模式(Bridge Pattern)

    一.引言 这里以电视遥控器的一个例子来引出桥接模式解决的问题,首先,我们每个牌子的电视机都有一个遥控器,此时我们能想到的一个设计是——把遥控器做为一个抽象类,抽象类中提供遥控器的所有实现,其他具体电视 ...

  4. 设计模式--桥接模式Bridge(结构型)

    一.概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或者多个维度的变化,如何应对这种"多维度的变化",就可以利用桥接模式. 引例: 设想如果要绘制矩形.圆形.椭圆.正方形,我 ...

  5. vmware中虚拟机与主机ping不通,桥接模式,IP地址在同一网段,无法互ping!

    现象描述:网卡选用的桥接模式,IP地址在同一个网段,虚拟机内部可以正常上网,但是Guest OS和Host OS无法互ping! 原因:虚拟机里的防火墙没有关闭,导致禁用ping功能. 解决方法:关闭 ...

  6. 桥接模式/bridge模式/对象结构型

    意图 将抽象部分与它的实现部分分离,使它们都可以独立的变化. 动机 当一个抽象类有多个实现时,通常用继承来协调它们.但是继承机制将抽象和实现固定,难以对抽象部分和实现部分独立地进行修改.扩充和重用. ...

  7. Objective-C 桥接模式 -- 简单实用和说明

    桥接模式---把两个相关联的类抽象出来, 以达到解耦的目的 比如XBox遥控器跟XBox主机, 我们抽象出主机和遥控器两个抽象类, 让这两个抽象类耦合 然后生成这两个抽象类的实例XBox & ...

  8. C#设计模式-桥接模式

    这里以电视遥控器的一个例子来引出桥接模式解决的问题,首先,我们每个牌子的电视机都有一个遥控器,此时我们能想到的一个设计是——把遥控器做为一个抽象类,抽象类中提供遥控器的所有实现,其他具体电视品牌的遥控 ...

  9. C#设计模式系列:桥接模式(Bridge)

    1.桥接模式简介 1.1>.定义 当一个抽象可能有多个实现时,通常用继承来进行协调.抽象类定义对该抽象的接口,而具体的子类则用不同的方式加以实现.继承机制将抽象部分与它的实现部分固定在一起,使得 ...

  10. 《JS设计模式笔记》 4,桥接模式

    //桥接模式的作用在于将实现部分和抽象部分分离开来,以便两者可以独立的变化. var singleton=function(fn){ var result; return function(){ re ...

随机推荐

  1. Autocad 2010+ObjectArx 2010 +Vs2010 的.net 开发设置(转)

    Autocad 2010+ObjectArx 2010 +Vs2010 的.net 开发设置 分类: ObjectArx.net2010-09-14 16:52 4203人阅读 评论(7) 收藏 举报 ...

  2. PHP代码实现 1

    $PHP-SRC/run-test.php 因为如果在同一个进程中执行, 测试就会停止,后面的测试也将无法执行,php中有很多将脚本隔离的方法比如: system(),exec()等函数,这样可以使用 ...

  3. Excel图片调整大小

    Excel图片调整大小 Sub 图片调整合适大小() ' Debug.Print ActiveWorkbook.Name 图片显示比例 = 0.9 '1为顶满单元格 Dim wb As Workboo ...

  4. WinForm各浏览器内核控件

    WebKit.NET webkit-sharp CefSharp awesomium OpenWebKitSharp geckofx MozNet Web Component

  5. Tornado模板转义处理

    转自:http://www.qttc.net/201305320.html tornado默认是转义所有字符,比较安全,但有时候我们的确需要把字符当做html来解析处理,因此我们需要做些处理. 示例: ...

  6. 六.jQuery源码分析之jQuery原型属性和方法

    97 jQuery.fn = jQuery.prototype = { 98 constructor: jQuery, 99 init: function( selector, context, ro ...

  7. Java下LDAP操作的资料

    话说LDAP真是个诡异的protocol(或者数据库,或者服务,whatever...),没有一个特别形象的spec.这里列出一些筛选出的还可以的文档,都是oracle的: https://docs. ...

  8. Java常用的转义字符

    以下为常用的转义字符对照表: 字母前面加上捺斜线"\"来表示常见的那些不能显示的ASCII字符.称为转义字符.如\0,\t,\n等,就称为转义字符. 转义字符 意义 ASCII码值 ...

  9. tfrecord

    制作自己的TFRecord数据集,读取,显示及代码详解 http://blog.csdn.net/miaomiaoyuan/article/details/56865361

  10. Redis 键空间通知

    [Redis 键空间通知] 键空间通知使得客户端可以通过订阅频道或模式, 来接收那些以某种方式改动了 Redis 数据集的事件. 以下是一些键空间通知发送的事件的例子: 所有修改键的命令. 所有接收到 ...