【转】设计模式学习笔记(7)-桥接

桥接(Bridge)这个词用的还是挺广的,意指将相似的但无法沟通的东西连接起来,比如说网桥就是连接两个网段的。

设计模式中的Bridge模式还是比较容易理解的,但是貌似不太常用,当然在GUI编程上用的还是比较多的。举个例子吧,面包长要生产几种类型的面包,如白面包(WhiteBread)和黑面包(BlackBread),当然我们有一个抽象的面包(Bread),现在的类图是这样的:

没有任何问题。
假如现在厂长为了扩展产品线,决定增加一种三角形面包,怎么办?如果按照现有的思路应该这样:

看出问题了,如果增加圆形的呢?这种设计就会造成子类爆炸。不但类太多不好管理,而且一旦黑面包更改了材料,所有相关的类都得修改,麻烦!

想到我们面向对象的设计的几个原则,依赖于抽象而不是实现,多用组合少用继承。
我们考虑到这个案例中有两个系列:颜色系列:黑面包和白面包;形状系列:三角形面包和长方形面包。
于是根据依赖抽象的原则至少有两个抽象类,分别是ColorBread和ShapeBread。那这两个抽象类怎样连接起来呢?利用组合,一个类另一个类的聚合。这样依赖地位就不平等了,于是我们将这两个类改名为Bread和BreadImpl:
类图应该是这样的:

根据这个类图写出代码是十分简单的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class BreadImpl
{
public:
    virtual string shape() = 0;
};
 
class Bread
{
private:
    BreadImpl* _impl;
public:
    void setImpl(BreadImpl* impl)
    {
        this->_impl = impl;
    }
    virtual string look()
    {
        return _impl->shape();
    }
};

从代码中可以看出Bread有一个BreadImpl类型的成员变量,并且有一个setImpl方法可以在运行时动态修改实现,这就是所谓的桥,也就是桥接模式的核心。BreadImpl有一个shape方法返回形状,而Bread类中有一个look方法返回面包的外观。
为这两个抽象类分别编写实现类。
BreadImpl的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TriaBread : public BreadImpl
{
public:
    string shape()
    {
        return "triangle";
    }
};
class RectBread : public BreadImpl
{
public:
    string shape()
    {
        return "rectangle";
    }
};

Bread的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class WhiteBread : public Bread
{
public:
    string look()
    {
        return Bread::look() + " White";
    }
};
class BlackBread : public Bread
{
public:
    string look()
    {
        return Bread::look() + " Black";
    }
};

最后在main方法里这样写:

1
2
3
Bread* bread = new BlackBread;
bread->setImpl(new RectBread);
cout << bread->look() << endl;

最终输出

1
rectangle Black

如果我们要修改成三角形的只需改成:

1
bread->setImpl(new TriaBread);

即可。可见这将抽象与它的实现分离了,这也正式Bridge模式的主要目的。

总的来说Bridge模式是十分简单的,变化也不多。不知大家有没有注意我们使用了setImpl来对实现进行设置。这里是否可以这样做还是值得商榷的,想到之前看过的抽象工厂模式,
我们完全在这里使用一个工厂来获得实例对象。另外也可以传一个参数,由Bread类根据参数信息查询对象列表来获取对象,这里又可以使用原型模式了。还有很多模式可以利用,设
计模式就是这样,每一个模式往往并不是单独使用的

最后来看看桥接模式的适用性:

  • 不希望在抽象和它的实现部分之间有一个固定的绑定关系,希望在程序运行时刻实现部分应可以被选择或者切换
  • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充
  • 对一个对象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译
  • 相对客户完全隐藏抽象的实现部分(针对C++)
  • 有许多类要生成的时候,并且可以明显感觉到可以将一个对象分解成两个部分
  • 想在多个对象间共享实现

总之,Bridge模式的核心就是将抽象部分与它的实现部分分离,这其实也是为了更低的耦合而设计的。

 

原文链接:http://lecoding.com/articles/175.html

posted on 2013-03-05 14:14  TheKingOfKingFish  阅读(126)  评论(0)    收藏  举报

导航