设计模式学习笔记--桥接模式
2016-05-08 15:49
381 查看
一.简介
今天来学习一下23种设计模式中的桥接模式。我们再设计系统时,如果某个类存在两个独立变化的维度,一种方案是使用多层继承,如果第一个维度有A个分支,第二个维度有B个分支的话,那么总共我们需要A*B个子类才能实现,这将是一个非常庞大的继承树。如果第一个维度增加了一个分支,那么我们需要再增加B个子类,扩展也变得很麻烦。而第二种方式就是我们今天要学习的桥接模式,通过桥接模式,我们可以将两个维度分离出来,使两者独立扩展,成为两个独立的继承树,并在最上层的抽象层中建立一个关联,这个关联就类似于连接两个独立结构的桥,所以我们称之为桥接模式。下面我们看一下桥接模式的定义以及桥接模式的UML类图:
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
简单解释一下桥接模式的UML类图,整体的继承树被拆分成两组继承树,以Abstraction为根的继承树和以Implementor为根的继承树。Abstraction通过一个抽象的接口调用Implementor,我们可以将Implementor的子类对象注入到Abstraction子类对象中,通过聚合的方式达到想要的效果。
二.桥接模式的例子
我们通过一个例子来看一下桥接模式的应用。我们现在要设计一个小游戏,包含几个兵种,男刀客,女刀客,男枪手,女枪手。怎么样设计这个人物的结构体系呢?我们分别看一下多层继承的情况和桥接模式的情况。1.多层继承的情况
// Design Pattern.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <string> #include <vector> using namespace std; //人物基类 class Character { public: virtual void Attack() = 0; }; //男人物 class MaleCharacter : public Character { public: virtual void Attack() = 0; }; //女人物 class FemaleCharacter : public Character { public: virtual void Attack() = 0; }; //男刀客 class PhysicalMaleChar : public MaleCharacter { public: virtual void Attack() { cout << "男角色: 物理攻击" << endl; } }; //女刀客 class PhysicalFemaleChar : public FemaleCharacter { public: virtual void Attack() { cout << "女角色: 物理攻击" << endl; } }; //男法师 class MagicMaleChar : public MaleCharacter { public: virtual void Attack() { cout << "男角色: 法术攻击" << endl; } }; //女法师 class MagicFemalChar : public FemaleCharacter { public: virtual void Attack() { cout << "女角色: 法术攻击" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { Character* character = new MagicFemalChar(); character->Attack(); system("pause"); return 0; }结果:
女角色: 法术攻击
请按任意键继续. . .
恩,虽然实现了想要的功能,不过如果我们的职业增加了几个,那么我们就要给每个新增的职业创建两个类,很麻烦。还是看看使用桥接模式的情况吧。
2.桥接模式的情况
// Design Pattern.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <string> #include <vector> using namespace std; //属性基类,相当于Implement类 class Attribute { public: virtual void Attack() = 0; }; //人物基类,相当于UML图中的Abstract类 class Character { protected: //保存一个属性的指针 Attribute* m_Attribute; public: //设置属性(职业) void SetAttribute(Attribute* attribute) { m_Attribute = attribute; } //攻击接口 virtual void Attack() = 0; }; //男人物 class MaleCharacter : public Character { public: virtual void Attack() override { cout << "男角色: "; m_Attribute->Attack(); } }; //女人物 class FemaleCharacter : public Character { public: virtual void Attack() override { cout << "女角色: "; m_Attribute->Attack(); } }; //物理属性 class PhysicalAttribute : public Attribute { public: void Attack() override { cout << "物理攻击" << endl; } }; //法系属性 class MagicAttribute : public Attribute { public: void Attack() override { cout << "法系攻击" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { Character* character = new FemaleCharacter(); Attribute* magicAttribute = new MagicAttribute(); character->SetAttribute(magicAttribute); character->Attack(); system("pause"); return 0; }结果:
女角色: 法系攻击
请按任意键继续. . .
我们使用了桥接模式,将人物性别和人物攻击的属性作为两个不同的属性,拆分成两个不同的继承树,然后在人物基类中保存一个人物属性的指针,使二者行程了聚合关系。这样,我们减少了冗余的类,大大减少了继承的复杂度,增强了复用性。在增加新类或者属性时,只需要增加新的属性类即可,符合开放-封闭原则。
三.桥接模式的总结
最后,我们来总结一下桥接模式的优点缺点以及使用时机。优点:
1)桥接模式是多层继承体系的一个很好的代替解决方案,大大减少了子类的个数,增加了复用性。
2)桥接模式分离了抽象接口以及实现部分,采用聚合方式,解耦了抽象和实现之间固有的绑定关系,让抽象和实现在不同的继承体系中实现。
3)桥接模式很好地提高了系统的扩展性,在扩展两个维度中任意一个维度时,都不需要修改原有内容,符合开放-封闭原则。
缺点:
1)桥接模式增加了系统的理解的难度,不如多层继承来得直接。
2)如何识别并分离两个维度比较困难,所以使用有一定的局限性。
使用时机:
如果我们的系统之前是使用多层继承方式实现的,在两个层次之间静态的继承关系不够灵活时,我们就可以考虑桥接模式。当我们的系统中存在两个或多个独立变化的维度,这两个维度都需要独立扩展,为了不让扩展的复杂度变成M*N,而是M+N的话,我们就可以使用桥接模式。
相关文章推荐
- Android setLayoutParams 常见问题汇总
- 升级Zabbix proxy到3.0.2后无法启动报错 推荐
- android adapter公共写法
- 深入分析字符编码之三-Java 中如何编解码
- 深入分析字符编码之二-Java 中需要编码的场景
- linux epoll 简单demo
- 深入分析字符编码之一-几种常见的字符编码格式
- [干货分享]浅谈seo如何提高网站权重
- 推荐阅读:Android开发者的博客
- Linux设备驱动(3)常用的宏、结构体、数据类型、函数等
- 山寨Besiege(三)需求分析与架构设计
- 计算机视觉、机器学习相关领域论文和源代码大集合--持续更新……
- IHS配置优化建议
- VMware Workstation Pro 导出OVF模板
- MySQL学习7:操作数据表(一)
- 侧栏工具栏
- 走神了
- Binder 简介
- 浅析中西思维差异对英语口语交际的影响
- linker command failed with exit code 1 (use -v to see invocation)