阿Sam的设计模式学习笔记---- Bridge模式

本文介绍桥接模式的基本概念,包括其功能、基本思想、适用情况和结构等,并通过绘图程序的例子展示了如何应用该模式来解决类的抽象及其实现之间的绑定问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,  功能:
    将抽象部分与它的实现部分分离,使它们都可以独立的变化。换言之,就是实现共同点与变化点的分离(主要是外部的变化),将变化点封装成类进行处理。
2,  基本思想:
    将时间的抽象与行为分开,使对象的属性与方法之间耦合度降低。只需要分别继承抽象的属性接口和方法接口就可以任意的“变化”具体对象的属性和方法。
3,  适用情况
    不希望在抽象和它的实现部分之间有一个固定的绑定关系。
Ÿ   类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。Bridge模式可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充。
Ÿ   对一个抽象的实现部分的修改对客户不产生影响,客户代码不必重新编译。
Ÿ   C++中,类的表示在类接口中是可见的,Bridge方式对客户完全隐藏抽象的实现部分。
Ÿ   希望在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这点。
4,  结构
说明:
(1)    Abstraction定义了抽象类的接口,它维护一个指向Implementor类型对象的指针;
(2)    RefinedAbstraction实现Abstraction接口的方法;RefinedAbstraction类的对象才是真正要“Implemented”的对象;
(3)    Implementor是实现类的接口,它不一定要求与Abstraction接口一致。一般来讲,Implementor接口仅提供基本操作,Abstraction定义的操作的具体实现通过Implementor接口的方法来实现。
(4)    ConcreteImpementor接口实现了Implementor接口。
5,  举例
    现在要设计一个绘图程序,可以画圆形和矩形。同时我们有两个不同版本的函数库,提供两套画图的实现(ShapeOneShapeTwo中分别调用两个库中的方法)。通常的实现方法,类的结构如下所示:
#include <iostream>
using namespace std;

// Draw with library 1
class CDrawLibOne
{
public
:
    
void DrawCircle(){cout << "Draw circle with lib one" <<
 endl;}
    
void DrawRectangle() {cout << "Draw rectangle with lib one" <<
 endl;}
};
// Draw with library 2

class CDrawLibTwo
{
public
:
    
void DrawCircle(){cout << "Draw circle with lib two" <<
 endl;}
    
void DrawRectangle() {cout << "Draw rectangle with lib two" <<
 endl;}
};

// CShapeOne class use library 1 to draw shapes

class CShapeOne
{
public
:
    virtual 
void Draw() = 0
;
protected
:
    CDrawLibOne m_lib;
};
//
 CCircleOne and CRectangleOne class are derived from CShape class.
// They use CDrawLibOne to draw.

class CCircleOne : public CShapeOne
{
    
void
 Draw() {m_lib.DrawCircle();}
};
class CRectangleOne : public
 CShapeOne
{
    
void
 Draw() {m_lib.DrawRectangle();}
};
// CShapeTwo class use library 2 to draw shapes

class CShapeTwo
{
public
:
    virtual 
void Draw() = 0
;
protected
:
    CDrawLibTwo m_lib;
};
//
 CCircleOne and CRectangleOne class are derived from CShape class.
// They use CDrawLibOne to draw.

class CCircleTwo : public CShapeTwo
{
    
void
 Draw() {m_lib.DrawCircle();}
};
class CRectangleTwo : public
 CShapeTwo
{
    
void
 Draw() {m_lib.DrawRectangle();}
};

// Define two global functions to draw with CShapeOne and CShapeTwo

void DrawOne(CShapeOne &s)
{
    s.Draw();
}
void DrawTwo(CShapeTwo &
s)
{
    s.Draw();
}

// The client use above classes to draw

int main()
{
    CCircleOne c1;
    CCircleTwo c2;
    CRectangleOne r1;
    CRectangleTwo r2;

    DrawOne(c1);
    DrawOne(r1);
    DrawTwo(c2);
    DrawTwo(r2);
    
return 1
;
}
    上面的代码运行起来没有问题,但是非常不便于维护,尤其是由于某种原因要求程序发生变化时。可能的变化是:需要添加新的函数库或者需要画新的图形(比如说画三角形)。假如现在要画三角形,那么按照之前的设计方案,需要定义CTriangle,修改库文件(最痛苦的修改)DrawLibOneDrawLibTwoCShapeOneCShapeTwo,添加画三角形的方法。上面的代码很小,如果库很复杂,类的结构也复杂,那么这种修改就是非常痛苦的。
   用Bridge模式来实现,就简单清晰了,并且易于扩展。Bridge模式最重要就是把表示和实现分开。结构图如下:
#include <iostream>
#include “stdafx.h”
using namespace std;

// Draw with library 1
class CDrawLibOne
{
public
:
    
void DrawCircle(){cout << “Draw circle with lib one” <<
 endl;}
    
void DrawRectangle() {cout << “Draw rectangle with lib one” <<
 endl;}
};
// Draw with library 2

class CDrawLibTwo
{
public
:
    
void DrawCircle(){cout << “Draw circle with lib two” <<
 endl;}
    
void DrawRectangle() {cout << “Draw rectangle with lib two” <<
 endl;}
};
// Implementation interface for CShape

class CShapeImp
{
public
:
    virtual 
void DrawCircle() = 0
;
    virtual 
void DrawRectangle() = 0
;
};
// Use Lib one to draw.

Class CShapeImpOne: public CShapeImp
{
public
:
    virtual 
void
 DrawCircle() {m_lib.DrawCircle();}
    virtual 
void
 DrawRectangle() {m_lib.DrawRectangle();}
private
:
    CDrawLibOne m_lib;
};
// Use Lib two to draw.

Class CShapeImpTwo : public CShapeImp
{
public
:
    virtual 
void
 DrawCircle() {m_lib.DrawCircle();}
    virtual 
void
 DrawRectangle() {m_lib.DrawRectangle();}
private
:
    CDrawLibTwo m_lib;
};

class
 CShape
{
public
:
    virtual 
void Draw() = 0
;
protected
:
    CShapeImp 
*
 m_Imp;
};
class CCircle : public
 CShape
{
public
:
    CCircle(CShapeImp 
* imp) {m_Imp =
 imp;}
    Virtual 
void Draw(){m_Imp->
DrawCircle();}
};
class CRectangle : public
 CShape
{
public
:
    CRectangle(CShapeImp 
* imp) {m_Imp =
 imp;}
    Virtual 
void Draw() {m_Imp->
DrawRectangle();}
};

// Start Drawing

void main()
{
    CShapeImpOne sImp1;
    CShapeImpTwo sImp2;

    
// Draw with the Library 1

    CCircle c1(&sImp1);
    CRectangle r1(
&
sImp1);
    C1.Draw();
    R1.Draw();

    
// Draw with the Library 2

    CCircle c2(&sImp2);
    CRectangle r2(
&
sImp2);
    C2.Draw();
    R2.Draw();
    Return;
}
    上面的代码是Bridge的实现。如果我们要想再画三角形,我们只需要在原有库的基础之上,建立一个新库实现画三角形的方法。然后,针对新的库定义新的CShapeImp类以及我们要画的CTriangle类。这样不会修改原有的库和类。符合设计模式原则中的“开闭原则”:软件实体应当对扩展开放,对修改关闭。
6,  总结
未使用Bridge模式的结构中,所有的类都处于一维空间,在同一条轴线上。要用哪个库来画哪个图形,用函数表示就是:Draw = f(Shape)
使用Bridge模式结构中,把变化的部分和不变的部分分别列在两个正交的坐标轴上,形成二维坐标系统。在随机系统中,正交的两个序列相关性最小。因此,Bridge模式就剥离了实现和表现。用函数表示为:Draw = f(Shape, Imp)
7,  相关模式
Abstract Factory模式可以用来创建和配置一个特定的Bridge模式
Adapter模式用来帮助无关的类协同工作,它通常在系统设计完成后才会被使用;Bridge模式则是在系统开始时就被使用,它使得抽象接口和实现部分可以独立进行改变。
 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值