概要
先考虑下在通信,电子等很多领域都常用的桥接概念,它的作用是什么?第一,它可以连接两个区域,第二,它可以隔离两个区域,简单来说也就是连接与分离的作用。而这里的 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模式。