[学习笔记]设计模式之Bridge

写在前面

为方便读者,本文已添加至索引html

“魔镜啊魔镜,谁是这个世界上最美丽的人?”月光中,一个低沉的声音回荡在女王的卧室。“是美丽的白雪公主,她正和小霍比特人们幸福快乐地生活在森林之中。”魔镜答道。“可恶!我才应该是最美的人,我要除掉你,白雪公主!”女巫开始用她的水晶球施展起诡异的妖术。设计模式

本来安宁的森林最近特别的闹腾,动物们个个都焦躁不安。小霍比特人之一的theWoodcutter(樵夫)在去伐木的路上发现了一头野熊的尸体。这头庞然大物的伤口上除了血淋淋的爪痕,居然混杂有烧焦的痕迹。他急急忙忙回到住处,和小伙伴们商量对策。他们首先想弄明白的是,究竟是什么入侵了本身的家园。框架

而这个世界的主人--时の魔导士,此刻正倚靠在木制的摇椅上,安详地抽着烟斗。他一回想起本身设计的这个虚拟的童话世界,脸上就露出了满意的笑容。他曾为小霍比特人们建造了武器工坊(见Factory Method笔记),Weapon是一个抽象类,它的子类包括Sword, Dagger, Bow等等都继承了Weapon的方法attack()。attack()能对敌人形成物理上的伤害……嗯,物理上的伤害。“彷佛这个还不太完美啊。在魔法的世界里,武器是能够被附魔Enchanted的。”魔导士嘟囔道,“好比,附上火焰的剑能轻易刺穿易燃的装甲,附上寒冰的箭矢也能够用来灭火呀。这想法有趣多了,让我来加点新鲜的东西给孩子们吧。”ide

附魔后的武器(EnchantedWeapon)的确是能够经过继承Weapon来获得,好比下图:函数

可是若是这样设计会有很糟糕的结果。武器种类不少,若是往后还要添加别的类型的武器,好比传奇的武器(EpicWeapon)每一个都带有史诗般的故事,装饰性的武器(DecoratedWeapon)比起杀伤力更注重外观等等。每添加一种武器分支,都会致使产生更多的子类。同时,若是咱们修改了Weapon的接口,那后续改动将很是巨大。学习

因而,时の魔导士引入了Bridge(桥接)模式,它将抽象部分与实现部分分离,从而很好地解决了上面所提到的问题。spa

要点梳理

  • 目的分类
    • 对象结构型模式
  • 范围准则
    • 对象(该模式处理对象间的关系,这些关系在运行时刻是能够变化的,更具动态性)
  • 主要功能
    • 将抽象部分与它的实现部分分离,使它们均可以独立地变化
  • 适用状况
    • 咱们不但愿在抽象和它的实现部分之间有一个固定的绑定关系。例如这种状况多是由于,在程序运行时刻实现部分应能够被选择或者切换
    • 类的抽象以及它的实现都应该能够经过生成子类的方法加以扩充。这时Bridge模式使咱们能够对不一样的抽象接口和实现部分进行组合,并分别对它们进行扩充
    • 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码没必要从新编译
    • 想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点
  • 参与部分
    • Abstraction:定义抽象类的接口;维护一个指向Implementor类型对象的指针
    • RefinedAbstraction:扩充由Abstraction定义的接口
    • Implementor定义实现类的接口,该接口不必定要与Abstraction的接口彻底一致;事实上这两个接口能够彻底不一样。通常来说,Implementor接口仅提供基本操做,而Abstraction定义了基于这些基本操做的较高层次的操做。
    • ConcreteImplementor:实现Implementor接口并定义它的具体实现。
  • 协做过程
    • AbstractionClient的请求转发给它的Implementor对象
  • UML图

示例分析 - 元素附魔武器诞生

利用桥接模式,咱们将各种武器抽象成Weapon类,它提供一个attack()的接口函数。对于武器的使用者,它只需操纵attack()便可。(发现这点和以前同样,对吧?可是别急)请看示例:设计

1 class Weapon {
2 public:
3     Weapon();   
4     virtual void attack();
5 protected:
6     WeaponImpl* getWeaponImpl();
7 private: 8 WeaponImpl* _impl; 9 }

注意到,Weapon它维护了一个对WeaponImpl的引用,而该抽象类定义了具体武器的操做的接口:指针

1 class WeaponImpl {
2 public:
3     virtual act() = 0;
4     virtual addEffect(const char*) = 0;
5 protected:
6     WeaponImpl();
7 }

如今,咱们能够将武器攻击动做的具体实现放在WeaponImpl的子类中,从而成功分离出Weapon类这个抽象概念。做为扩展,附魔武器EnchantedWeapon类以下: code

 1 class EnchantedWeapon : public Weapon {
 2 public:
 3     EnchantedWeapon(char*);
 4     virtual void attack();
 5 private:
 6     const char* _element;
 7 }
 8 
 9 EnchantedWeapon::EnchantedWeapon(char* e):_element(e) {}
10 
11 void EnchantedWeapon::attack() {
12     WeaponImpl* impl = getWeaponImpl();
13     
14     if (impl != 0) {
15         impl->addEffect(_element);
16         impl->act();
17     }
18 }

EnchantedWeapon能够为武器附上不一样程度的魔法效果,而后经过调用WeaponImpl类的act操做来行动。具体的WeaponImpl类则根据自身状况来实现act操做,剑能够用来挥舞和刺击,弓箭则要上满弦,等等。咱们看这里的SwordImpl

 1 class SwordImpl : public WeaponImpl {
 2 public:
 3     SwordImpl(int);
 4     virtual void addEffect(const char*);
 5     virtual void act();
 6 private:
 7     int _damage;
 8     char* _effect;
 9 }
10 
11 SwordImpl::SwordImpl(int d) {
12     _damage = d;
13 }
14 
15 void SwordImpl::addEffect(const char* e) {
16     if (_effect)
17     {
18         delete _effect;
19     }
20     _effect = new char[strlen(e)+1];
21     strcpy(_effect, e);
22 }
23 
24 void SwordImpl::act() {
25     if (_effect)
26     {
27         cout << "Wielding sword with " << _effect << endl;
28     }
29     else
30     {
31         cout << "Wielding sword" << endl;
32     }
33 }
SwordImpl

一样的对于BowImpl来讲,效果是在箭矢上的:

 1 class BowImpl : public WeaponImpl {
 2 public:
 3     BowImpl(int);
 4     virtual void addEffect(const char*);
 5     virtual void act();
 6 private:
 7     int _damage;
 8     char* _effect;
 9 }
10 
11 BowImpl::BowImpl(int d) {
12     _damage = d;
13 }
14 
15 void BowImpl::addEffect(const char* e) {
16     if (_effect)
17     {
18         delete _effect;
19     }
20     _effect = new char[strlen(e)+1];
21     strcpy(_effect, e);
22 }
23 
24 void BowImpl::act() {
25     if (_effect)
26     {
27         cout << "Shoot an arrow with " << _effect << endl;
28     }
29     else
30     {
31         cout << "Shoot an arrow" << endl;
32     }
33 }
BowImpl

一个简单的UML图来讲明上面的模式:

在这套框架下,不管咱们是继续添加EpicWeapon,仍是具体的DaggerImpl等,都很是方便。顺便说下,咱们能够用Weapon提供的getWeaponImpl方法来得到想要的武器实现。具体代码在此就不做详解了(能够利用抽象工厂或者单例等对象建立型模式来作)。

特色总结

Bridge模式有如下几个优势:

  1. 分离接口及其实现部分。一个实现未必不变地绑定在一个接口上。抽象类的实现能够在运行时刻进行配置,一个对象甚至能够在运行时刻改变它的实现。将AbstractionImplementor分离有助于下降对实现部分编译时刻的依赖性,当改变一个实现类时,并不须要从新编译Abstraction类和它的客户程序。为了保证一个类库的不一样版本之间的二进制兼容性,必定要有这个性质。
  2. 提升可扩充性。咱们能够独立地对AbstractionImplementor层次结构进行扩充。
  3. 实现细节对客户透明

须要注意的是,若是咱们仅有一个Implementor,能够没有必要建立一个抽象的Implementor类。这是Bridge模式的退化状况;在AbstractionImplementor之间有一种一对一的关系。

写在最后

森林里的中间有一只凶狠的魔法生物,混身散发着火焰,周围是烧焦的树木。它彷佛被顽强的霍比特人激怒了,咆哮了起来。仅凭普通的武器,小霍比特人们没法打败这只凶兽,他们中已有好几人身负重伤了。在危在旦夕之刻,武器工坊发出耀眼的光芒,白雪公主从中拿出了一把镶满冰晶的奇弓,附着了寒冰的魔法。公主拉起弓弦瞄准了火兽,“真正的战斗如今才开始呢!” ......

今天的笔记就到这里了,欢迎你们批评指正!若是以为能够的话,好文推荐一下,我会很是感谢的!

相关文章
相关标签/搜索