JAVA设计模式(19) —桥接(Bridge)模式

定义:将抽象部分与它的实现部分分离,使它们可以独立的变化。

类型:对象结构型模式

类图:

JAVA设计模式(19) —桥接(Bridge)模式_第1张图片

桥接模式的结构

  • Abstraction :抽象类的接口,维护一个指向Implementor类型对象的指针,在本例中为 IPluginPlatform。
  • RefinedAbstraction :扩充Abstraction定义的接口,在本例中为 PluginVersionA、PluginVersionB。
  • Implementor :定义实现类的接口,该接口不一定要与Abstraction 完全一致;事实上,这两个接口可以完全不同。一般来讲 Implementor 接口仅提供基本操作,而Abstraction 则定义了基于这些基本操作的较高层次的操作。
  • ConcreteImplementor :实现Implementor 并定义它的具体实现。


示例

假设要为一个系统设计插件,首先这个系统是需要跨平台的,其次,由于插件经常会版本升级,所以系统需要支持多多个版本插件。顺着需求,我们可能会这样去考虑解决方案。
因为需要跨平台,那么通过抽象和继承来实现跨平台。
JAVA设计模式(19) —桥接(Bridge)模式_第2张图片

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

JAVA设计模式(19) —桥接(Bridge)模式_第3张图片

代码如下:



abstract class IPlugin {
	public abstract void loadPlugin();

	public abstract void unloadPlugin();

	public void start() {
		// add operation
	}

	public void stop() {
		// add operation
	}
}

class WindowsPlugin extends IPlugin {
	@Override
	public void loadPlugin() {
	}

	@Override
	public void unloadPlugin() {
	}
}

class WinPluginVer1 extends WindowsPlugin {
	@Override
	public void start() {
		loadPlugin();
		super.start();
	}

	@Override
	public void stop() {
		unloadPlugin();
		super.stop();
	}
}

class WinPluginVer2 extends WindowsPlugin {
	@Override
	public void start() {
		loadPlugin();
		super.start();
	}

	@Override
	public void stop() {
		unloadPlugin();
		super.stop();
	}
}

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

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

Bridge模式实现代码

//抽象类接口 --> 插件
abstract class IPlugin{
	protected IPluginPlatform platform;

	public void setPlatform(IPluginPlatform platform) {
		this.platform = platform;
	}
	
	public abstract void start();
	public abstract void stop();
}

//不同 版本号 实现
class PluginVersionA extends IPlugin{

	@Override
	public void start() {
		platform.loadPlugin();
	}

	@Override
	public void stop() {
		platform.unloadPlugin();
	}
}
class PluginVersionB extends IPlugin{

	@Override
	public void start() {
		platform.loadPlugin();
	}

	@Override
	public void stop() {
		platform.unloadPlugin();
	}
}

//抽象类接口 --> 平台
abstract class IPluginPlatform{
	
	public abstract void loadPlugin();

	public abstract void unloadPlugin();
}

//Windows平台实现
class WindowsPlugin  extends IPluginPlatform{

	@Override
	public void loadPlugin() {
		System.out.println("WindowsPlugin loading ...");
	}

	@Override
	public void unloadPlugin() {
		System.out.println("WindowsPlugin unLoading ...");
	}
}

class LinuxPlugin  extends IPluginPlatform{

	@Override
	public void loadPlugin() {
		System.out.println("LinuxPlugin loading ...");
	}

	@Override
	public void unloadPlugin() {
		System.out.println("LinuxPlugin unLoading ...");
	}
}

//客户端调用
public class BridgeClient {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		IPlugin plugin = new PluginVersionA();
		
		IPluginPlatform platform = new WindowsPlugin();
		plugin.setPlatform(platform);
		
		plugin.start();
		plugin.stop();
	}
}

桥接模式适用场景

  1. 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。
  2. 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。
  3. 对一个抽象的实现部分的修改应对客户不产生影响,即客户端的代码不必重新编译。
  4. (C++)你想对客户完全隐藏抽象的实现部分。
  5. 你想在多个实现间 共享实现,但同时要求客户并不知道这一点。


桥接模式的优点

  • 分离接口及其实现部分。一个实现未必不变地邦定在一个接口上。抽象类的实现可以在运行的时刻进行配置,一个对象甚至可以在运行的时候改变它的实现。

将Abstraction和Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。

另外接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。

  • 提高可扩充性。你可以独立地对Abstraction和Implementor层次结构进行扩充。
  • 实现细节对客户的透明。你可以对客户隐藏实现细节。



你可能感兴趣的:(JAVA设计模式(19) —桥接(Bridge)模式)