【设计模式攻略】结构型模式之Bridge模式

来源:互联网 发布:网络推广sem 编辑:程序博客网 时间:2024/04/30 22:41
概要
先考虑下在通信,电子等很多领域都常用的桥接概念,它的作用是什么?第一,它可以连接两个区域,第二,它可以隔离两个区域,简单来说也就是连接与分离的作用。而这里的 Bridge模式也是类似,它可以分离系统的不同层次,使不同层次的实现可以相互独立的变化,同时它又为不同层次间建立起了连接进行交互。

目的
 Bridge模式,比较教条或比较官方的定义是,可以分离抽象与实现,并使它们可以相互独立的变化。我的理解让我对常规的定义略加补充,我的观点是,它可以通过抽象与实现的分离,来分离系统中不同层次的功能,使不同层次间可以相互独立的变化。

实例
上面的说明都比较抽象,还是用实例来打动大家吧。看这样一个例子。
假设要为一个系统设计插件,首先这个系统是需要跨平台的,其次,由于插件经常会版本升级,所以系统需要支持多多个版本插件。顺着需求,我们可能会这样去考虑解决方案。
因为需要跨平台,那么通过抽象和继承来实现跨平台。

又因为每个平台都需要支持多个插件版本,那就继续在每个平台下扩展不同版本吧。

代码如下:
class IPlugin {public:       virtual void LoadPlugin() = 0;       virtual void UnloadPlugin() = 0;       virtual void Start() = 0;       virtual void Stop() = 0;};class WindowsPlugin : public IPlugin {public:       virtual void LoadPlugin() {              ......       }       virtual void UnloadPlugin() {              ......       }};class WinPluginVer1 : public WindowsPlugin {public:       virtual void Start() = 0 {              ...... // do something for Ver1              LoadPlugin();       }       virtual void Stop() = 0 {              UnloadPlugin();              ...... // do something for Ver1       }};class WinPluginVer2 : public WindowsPlugin {public:       virtual void Start() = 0 {              ...... // do something for Ver2              LoadPlugin();       }       virtual void Stop() = 0 {              UnloadPlugin();              ...... // do something for Ver2       }};

这里省略 windows以外平台, 以及 Ver1,2以外版本的代码。
以上确实是一种解决方法,但却不是一种好方法。试想一下如果现在又多出一种平台了怎么办?只能再加一个继承分支,同时对这个平台也需要追加多个版本的实现。而如果又升级了一个版本怎么办?只能在每种平台下都追加该版本的实现。类结构就膨胀成如下这样:

现在可以看出,平台和版本这系统中两个层次的实现被耦合在一起,导致每次功能追加都伴随着重复的实现和类的膨胀。很难想象,当再追加 n个平台,和 n个版本的支持后,系统结构会爆炸式的膨胀成什么样!伴随着的还有设计,编码,测试等成本以及风险的成倍增加。

怎么解决上面的问题, OK,该 Bridge模式登场了。
首先,让我们把平台和版本这两个层次间的耦合分离开来,分离出各自的抽象与实现。
class IPluginPlatform {public:       virtual void LoadPlugin() = 0;       virtual void UnloadPlugin() = 0;};class WindowsPlugin : public IPluginPlatform {public:       virtual void LoadPlugin() {              ......       }       virtual void UnloadPlugin() {              ......       }};class IPlugin {public:       virtual void Start() = 0;       virtual void Stop() = 0;};class PluginVer1 : public IPlugin {public:       virtual void Start();       virtual void Stop();};

既然是 Bridge,在分离的同时也需要连接,怎么连接呢?很简单,进一步完善下 IPlugin PluginVer1 ,代码如下所示:
class IPlugin {public:       IPlugin(IPluginPlatform* plugin) {              mPluginPF = plugin;       }       void LoadPlugin() {              mPluginPF->LoadPlugin();       }       void UnloadPlugin() {              mPluginPF->UnloadPlugin();       }       virtual void Start() = 0;       virtual void Stop() = 0;private:       IPluginPlatform* mPluginPF;};class PluginVer1 : public IPlugin {public:       virtual void Start() = 0 {              ...... // do something for Ver1              LoadPlugin();       }       virtual void Stop() = 0 {              UnloadPlugin();              ...... // do something for Ver1       }};class PluginVer2 : public IPlugin {public:       virtual void Start() = 0 {              ...... // do something for Ver2              LoadPlugin();       }       virtual void Stop() = 0 {              UnloadPlugin();              ...... // do something for Ver2       }};
IPlugin 包含了当前对应的 Plugin平台对象,通过该对象实现 LoadPlugin UnloadPlugin方法,而在其子类中不再需要去关心到底是使用哪个平台相关对象,只需要直接通过父类 IPlugin LoadPlugin UnloadPlugin方法进行插件加载卸载就可以了。
从如下类图可以更清晰的看出所谓 Bridge模式中类桥接的关系。通过 Bridge模式,分离了平台和版本这两个层次,使它们各自能够相对独立的扩展。不管是多支持一个平台还是多支持一种版本,都只需要扩展追加一个相应的类就可以实现,结构层次分明,使用也非常方便。
应用
当需要分离不同层次功能间的耦合,分离抽象与实现时,可以采用 Bridge模式。当然,前提是分析清楚真正的需求,滥用 Bridge模式也会让本来很简单清晰的应用变得既冗余又复杂。另外,可以通过 Abstract Factory模式来创建 Bridge模式中一端的具体实现(如上的 IPluginPlatform的子类对象),详细情况请参照 Abstract Factory模式。

原创粉丝点击