您的位置:首页 > 其它

【设计模式学习笔记八】【结构型模式】【桥接模式(Bridge)】

2015-01-26 19:48 639 查看
本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》的笔记,博客链接:/article/1610242.html

主要是对刘伟博客和书本做提炼和记录,方便自己查阅,更多是对设计模式的基础框架学习,细节都将略去,侧重对每个设计模式框架的理解。

我应该理解和掌握的:

1)能够画出这个设计模式的架构框图;

2)能够根据架构框图写出对应的伪代码;

3)这个模式的应用场景,主要优缺点。

1.桥接模式(Bridge)

假如我们需要三种型号不同的大、中、小,并各包含红色,绿色,黑色的蜡笔,总要需要3*3=9条蜡笔;那么如果换成三种颜色的颜料和3只不同型号的毛笔,那么只需要6种类型。蜡笔相当于颜色和型号这两种职责结合在一起了,耦合性高;而毛笔和颜料则很好的区分出各自的自责;比如增加一种颜色,需要增加3条蜡笔,而后者只简单需要一种颜料,扩展性好,松耦合。把笔和颜料分离,是两者可以独立扩展,让系统更加符合单一职责。桥接模式便可以很好的处理这种多维度变化的关系,将两个独立变化的维度设计为两个独立的继承等级结构,并且在抽象层建立抽象关联,该关联关系类似于一条连接两个继承结构的桥,故名为桥接模式。

(1)定义

将抽象部分与他的实现部分分离,使他们都可以独立的变化;用抽象关联取代传统的多层继承,将类之间的静态继承关系转换为动态对象组合关系,是系统更加灵活,并易于扩展,同时有效控制系统中类的个数。
1) 桥接模式的结构图,存在一条连接两个继承等级结构的桥



2)参与者:
a) Abstraction(抽象类):定义抽象类的接口;关联、维护一个指向Implementor类型对象的指针。
b) RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口。
c) Implementor(实现类接口):定义实现类的接口,该接口不一定要和Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstractioin则定义了基于这些基本操作的较高层次的操作。
d) ConcreteImplementor(具体实现类):实现Implementor接口并定义它的具体实现,不同的具体实现类基本操作不同。
e) 使用桥接模式时,我们应该首先识别出两个独立变化的维度,为两个维度都提供抽象层,并建立抽象耦合。通常,将一些普通业务方法与之关系最密切的设计为抽象类层次结构,另一维度设计为实现类层次结构。例如,对毛笔而言,型号是固定维度,可以设置抽象的毛笔类,即抽象部分,颜色为是实现部分。
e) 看图写代码:

#include <stdio.h>
#include "Implementor.h"
//抽象类部分
class Abstraction
{
public:
    Abstraction(Implementor* im)
    {
        Impl = im;
    }
    virtual ~Abstraction()
    {
        if(Impl != NULL)
        {
            delete Impl;
            Impl = NULL;
        }
    }
    virtual void operation() = 0;
    Implementor* getImplementor()
    {
        return Impl;
    }
private:
    Implementor* Impl; //关联实现部分父类
};
//继承父类,实现大 中 小各种子类
class ConcreteAbstraction:public Abstraction
{
public:
    ConcreteAbstraction(Implementor* im):Abstraction(im)
    {
    }
    void operation()
    {
        //设置各种型号和颜色的笔
        cout<<"set big and ";
        getImplementor()->setColor();
    }
};
//实现类部分
class Implementor
{
public:
    Implementor(){}
    virtual ~Implementor(){}
    virtual void setColor() = 0;
};
//继承父类,实现各种颜色的子类
class ConcreteImplementor:public Implementor
{
public:
    virtual void setColor()
    {
        //红色
        cout<<"red pen"<<endl;
    }
};
//客户端调用
int main(int argc, const char * argv[]) {
    //针对抽象编程,生成不同的颜色子类
    Implementor *im = new ConcreteImplementor();
    //生成不同型号的毛笔子类,并注入颜色具体实现类
    Abstraction *ab = new ConcreteAbstraction(im);
    //输出型号,颜色
    ab->operation();
    return 0;
}


(2)总结

1)优点:
a)
分离接口及其实现部分。对象间关联解耦了抽象和实现之间的固有绑定关系,使得抽象和实现可以沿着各自的维度变化,也就是抽象和实现不再同一个继承层次结构中,而是子类化他们,使他们有各自的子类。系统高层只需要知道Abstraction和Implementor。
b)
提高可扩充性。独立的对Abstraction和Implementor层次结构进行扩充,不影响原有系统,符合开闭原则。
c)
很多情况下,桥接模式可以取代多层继承方案,多层继承违背单一职责原则,复用性差,类的个数多。
2)缺点:
a) 桥接模式会增加系统的理解和设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
b) 桥接模式要求正确的识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性,如何识别出两个独立的维度也需要一定的经验积累。

(3)适用场景

1) 如果不希望在抽象和他的实现部分之间有一个固定的绑定关系(继承关系),并且在程序运行时刻实现部分可以被选择或者切换。
2)类的抽象部分和实现部分都应该可以通过生成子类的方法加以扩充并且互不影响。动态的将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
3)一个类存在两个或多个独立变化的维度,且这两个(或多个)维度都需要独立进行扩展,抽象出这些变化维度,将依赖具体实现改为依赖抽象。
4)对于不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
5)如要要求对一个抽象的实现部分的修改对客户不产生影响,即客户的代码不需要重新编译。
6)如果某个变化因素在多个对象中共享时,可以抽象出这些变化因素,然后实现这些不同的变化因素。
7)桥接(Birdge)模式和适配器(Adapter)模式适用于设计的不同阶段。适配器用来帮组无关的类协同工作,通常用在系统设计完成后才会被使用;桥接模式则是在系统开始时就被使用,他使得抽象接口和实现部分可以独立进行改变。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: