本文在准备时,参考了以下博客和《大话设计模式》
https://www.cnblogs.com/lfxiao/p/6815760.html
http://www.cnblogs.com/chenssy/p/3317866.html
1. 使用桥接模式的时机:
当我们需要多角度去分类实现对象,一昧的继承会造成大量类的增加,不能满足开放-封闭原则(增加开放,修改封闭)时,就应该要考虑用桥接模式了。
2. “多角度” 概念实例
上面提到 “多角度”,听起来比较抽象,举个例子:
我们现在准备作图工具。
要求:可以画出3种规格大小、12种颜色的线条。
如果我们使用蜡笔,需要准备3*12=36个不同种类的蜡笔。
如果我们使用毛笔,则只需要3种毛笔,外加12种颜色的颜料。
3+12=15 远小于 36。
以上两种方案的区别在于:选择毛笔时,我们将通过 “大小” 和 “颜色” 两个维度分别寻找解决方案,三种大小的毛笔+12种颜料的方案,要比准备36种蜡笔的方案简洁很多。
3. 桥接模式的定义
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。
桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。
抽象化:其概念是将复杂物体的一个或几个特性抽出去而只注意其他特性的行动或过程。
实现化:针对抽象化给出的具体实现。它和抽象化是一个互逆的过程,实现化是对抽象化事物的进一步具体化。
脱耦:脱耦就是将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联,将两个角色之间的继承关系改为关联关系。
《大话设计模式》里面的就是实现系统可能有多个角度分类,每一种角度都可能变化,那么把这种多角度分类给分离出来让他们独立变化,减少他们之间耦合。
桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。
4. 桥接模式UML结构图
![](https://i-blog.csdnimg.cn/blog_migrate/83c086c1042c36c18d442bd455785288.png)
上图中:
Abstraction:抽象类。 它一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。
RefinedAbstraction:扩充抽象类。它实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法。
Implementor:实现类接口。 这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在Abstraction中不仅拥有自己的方法,还可以调用到Implementor中定义的方法,使用关联关系来替代继承关系。
ConcreteImplementor:具体实现类。在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法
5. 一种桥接模式的实现
本文继续以作图为例:
要求:实现多种不同颜色、不同形状的数学图形。
我们形状和颜色两个维度分别抽象出来:一个(形状)作为抽象类,一个(颜色)作为抽象类中要调用的接口。
![](https://i-blog.csdnimg.cn/blog_migrate/4ba89a39fa4e3afb701dfee72625772f.png)
首先是形状类:该类为一个抽象类,主要提供画形状的方法:Shape.java
public abstract class Shape {
Color color;
public void setColor(Color color) {
this.color = color;
}
public abstract void draw();
}
三种形状类,分别如下:
长方形:ReckAngle.java
public class Rectangle extends Shape{
public void draw() {
color.paint("长方形");
}
}
圆形:Circle.java
public class Circle extends Shape{
public void draw() {
color.paint("正方形");
}
}
正方形:Square.java
public class Square extends Shape{
public void draw() {
color.paint("正方形");
}
}
然后是颜色接口:Color.java
public interface Color {
public void paint(String shape);
}
接下来是三种颜色实现类:
白色:White.java
public class White implements Color{
public void paint(String shape) {
System.out.println("白色的" + shape);
}
}
红色:Red.java
public class Red implements Color{
public void bepaint(String shape) {
System.out.println("红色的" + shape);
}
}
黑色:Black.java
public class Black implements Color{
public void bepaint(String shape) {
System.out.println("黑色的" + shape);
}
}
客户端:Client.java
public class Client {
public static void main(String[] args) {
//白色
Color white = new White();
//正方形
Shape square = new Square();
//白色的正方形
square.setColor(white);
square.draw();
//长方形
Shape rectange = new Rectangle();
//白色的长方形
rectange.setColor(white);
rectange.draw();
}
}
运行结果:
白色的正方形
白色的长方形
6. 桥接模式的适用场景
1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。