23.桥梁模式(Bridge Pattern)

1.定义

将抽象和实现解耦,使得两者可以独立地变化

 

2.例子

定义看不明白?没关系,我将通过下面这个例子来阐述桥梁的概念。

 

小时候我们都用蜡笔画画,一盒蜡笔12种颜色。一开始我都是用最小号的蜡笔画个太阳公公、月亮婆婆足够了。后来开始画一些抽象派的作品,就得换中号的了,要不然画个背景都要描半天,好一盒中号的也是12种颜色。再后来我开始转向豪放派,中号就有些捉襟见肘了,只好换大号的了,好一盒大号的也只有12种颜色。你看,像我这样不太出名的画家就需要36种画笔,哇,太麻烦了。但是据我观察,另一些比我出名的画家倒是没有这么多笔,他们只有几把刷子和一些颜料,这样就解决了蜡笔的“种类爆炸”问题。”

 

 

==========================================================

 

呵呵,您是不是已经看出来了,不错,我今天要说的就是Bridge模式。为了一幅画,我们需要准备36支型号不同的蜡笔,而改用毛笔三支就够了,当然还要搭配上12种颜料。通过Bridge模式,我们把乘法运算3×12=36改为了加法运算3+12=15,这一改进可不小。那么我们这里蜡笔和毛笔到底有什么区别呢?

 

实际上,蜡笔和毛笔的关键一个区别就在于笔和颜色是否能够分离。【GOF95】桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。关键就在于能否脱耦。蜡笔的颜色和蜡笔本身是分不开的,所以就造成必须使用36支色彩、大小各异的蜡笔来绘制图画。而毛笔与颜料能够很好的脱耦,各自独立变化,便简化了操作。在这里,抽象层面的概念是:"毛笔用颜料作画",而在实现时,毛笔有大中小三号,颜料有红绿蓝等12种,于是便可出现3×12种组合。每个参与者(毛笔与颜料)都可以在自己的自由度上随意转换。

 

蜡笔由于无法将笔与颜色分离,造成笔与颜色两个自由度无法单独变化,使得只有创建36种对象才能完成任务。Bridge模式将继承关系转换为组合关系,从而降低了系统间的耦合,减少了代码编写量。

 

桥梁模式是一种非常简单的模式,它只是使用了类间的聚合关系、继承、重写等常用功能,但是它却提供了一个非常清晰、稳定的架构。

 

下面还有个小例子:

 

 

====================================================

 

 

 

3.桥梁模式的使用场景

  • 不希望或不适合使用继承的场景:例如继承层次过渡、无法更细化设计颗粒等场景,需要考虑使用桥梁模式
  • 接口或抽象类不稳定的场景:明知道接口不稳定还想通过实现或继承来实现业务需求,那是得不偿失的,也是比较失败的做法
  • 重用性要求比较高的场景:设计的颗粒度越细,则被重阳的可能性越大,而采用继承则受父类的限制,不可能出现太细的颗粒度

4.桥梁模式的四个角色

  • Abstraction-抽象化角色(上图中的毛笔):它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类。
  • Implementor-实现化角色(上图中的颜料):它是接口或者抽象类,定义角色必须的行为和属性。
  • RefinedAbstraction-修正抽象化角色:它引用实现化角色对抽象化角色进行修改。
  • ConcreteImplementor-具体实现化角色:它实现接口或抽象类定义的方法和属性。

下面是它们的类图:

 

5.桥梁模式的通用代码

package _23BridgePattern;

/**
 * 实现化角色
 * (颜料)
 */
public interface Implementor {

	// 基本方法
	// 画图
	public void paint();
	// 提名
	public void title();
}
 
package _23BridgePattern;

/**
 * 具体实现化角色
 * (假装红颜料)
 */
public class ConcreteImplementor1 implements Implementor {

	@Override
	public void paint() {
		System.out.println("使用红色颜料画画");
	}

	@Override
	public void title() {
		System.out.println("使用红色颜料提名");
	}

}
 
package _23BridgePattern;

/**
 * 具体实现化角色
 * (假装蓝颜料)
 */
public class ConcreteImplementor2 implements Implementor {

	@Override
	public void paint() {
		System.out.println("使用蓝色颜料画画");
	}

	@Override
	public void title() {
		System.out.println("使用蓝色颜料提名");
	}

}
 
package _23BridgePattern;

/**
 * 抽象化角色
 * (假装毛笔)
 */
public abstract class Abstraction {

	// 定义对实现化角色的引用
	private Implementor implementor;
	// 约束子类必须实现该构造函数
	public Abstraction(Implementor implementor) {
		this.implementor = implementor;
	}
	
	// 自身的行为和属性
	public void paint() {
		this.implementor.paint();
	}

	public Implementor getImplementor() {
		return implementor;
	}
}
 
package _23BridgePattern;

/**
 * 具体抽象化角色
 * (假装小号毛笔)
 *
 */
public class RefinedAbstraction extends Abstraction {

	public RefinedAbstraction(Implementor implementor) {
		super(implementor);
	}

	// 修正父类的行为
	@Override
	public void paint() {
		super.paint();
		super.getImplementor().title();
	}
}
 
package _23BridgePattern;

/**
 * 场景类 
 */
public class Client {

	public static void main(String[] args) {
		// 定义一个实现化角色(颜料)
		// 还可以定义别的颜色
		Implementor implementor = new ConcreteImplementor1();
		// 定义一个抽象化角色(毛笔)
		// 还可以定义别的大小的毛笔
		Abstraction abstraction = new RefinedAbstraction(implementor);
		// 执行(画画),这样你画画就不需要36支笔了,只需要三支笔,12种颜料就行了
		abstraction.paint();
	}

}

6.桥梁模式的优点

  • 抽象和实现分离:这也是桥梁模式的主要特点,它完全是为了解决继承的缺点而提出的设计模式。在该模式下,实现可以完全不受抽象的约束,不用再绑定在一个固定的抽象上。
  • 优秀的扩展能力:看看我们的例子,想增加毛笔大小和颜料色彩都完全没问题,我们已经把变化的可能性减到了最小。
  • 实现细节对客户透明:客户不必关心细节的实现,它已经由抽象层通过聚合完成了封装。

7.桥梁模式的注意事项

  • 桥梁模式是非常简单的,使用该模式时,主要考虑如何拆分抽象和实现,并不是一涉及继承就要考虑桥梁模式,那还要继承干什么呢?桥梁模式的意图是对变化的封装,尽量把可能变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。
  • 桥梁模式:将抽象化与实现化脱耦,使得二者可以独立的变化,也就是说将他们之间的强关联变成弱关联,也就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以独立的变化。

猜你喜欢

转载自wangwengcn.iteye.com/blog/1735503