名称
桥接模式(BRIDGE),别名:Handle/Body
目的
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
适用性
以下一些情况使用Bridge模式:
不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。
类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge模式使可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
想对客户完全隐藏抽象的实现部分。
想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
如下图所示的那样,有许多类要生成。当这种类层次结构(这种类层次结构可以称为“嵌套的普化”)必须将一个对象分解成两个部分,此时可以使用此模式。
结构
抽象(Abstraction):
定义抽象类的接口。
维护一个指向Implementor类型对象的指针。
扩展抽象(RefinedAbstraction):扩充由Abstraction定义的接口。
实现(Implementor):定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
具体实现(ConcreteImplementor):实现Implementor接口并定义它的具体实现。
tips:方法的传递顺序为 抽象 -> 扩展抽象 -> 实现 -> 具体实现
协作
Abstraction将client的请求转发给它的Implementor对象。
效果
优点
分离接口及其实现部分。一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。
将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。另外,接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。
提高可扩充性。可以独立地对Abstraction和Implementor层次结构进行扩充。
实现细节对客户透明。可以对客户隐藏实现细节,例如共享Implementor对象以及相应的引用计数机制(如果有的话)。
符合开闭原则。桥接模式允许在不修改现有代码的情况下添加新的实现。
合成复用原则。通过组合不同的抽象和实现,可以创建多种多样的产品(不用像抽象工厂类那样有很多类)。
缺点
增加了系统的复杂度。桥接模式引入了更多的类和接口,这可能会使系统的设计更加复杂。
设计难度提高。要求开发者从一开始就需要考虑抽象层次的设计,并且要能够正确识别系统中的两个独立变化维度。
可能的性能影响。如果实现部分需要频繁地切换,可能会导致性能上的损失。
应用
问题
当我们使用电脑的绘图工具绘制形状的时候,首先会选择形状,然后会选择颜色(一般默认是黑色)进行绘制,假设形状有圆形、长方形、正方形,颜色有黑色、灰色、白色,此时可以分离抽象部分和实现部分(这里为了演示使用桥接模式)。绘制形状为抽象、绘制具体形状为扩展抽象;使用颜色绘制形状为实现,使用具体颜色绘制形状为具体实现。绘制什么形状由扩展抽象对象实现,绘制什么颜色的形状由扩展抽象对象的Implementor对象实现,这样就实现了抽象和实现的分离。
示例
UML
代码示例
抽象:形状,有成员变量Color,和绘图方法draw(),setColor()设计为可链式调用
package com.ysj.part4.bridge.normal.abstraction;
import com.ysj.part4.bridge.normal.implementor.Color;
public abstract class Shape {
public Color color;
public Shape setColor(Color color) {
this.color = color;
return this;
}
public abstract void draw();
}
扩展抽象:圆形、矩形、正方形,继承Shape,并且重写draw()方法,draw方法使用Color对象调用bepaint()
package com.ysj.part4.bridge.normal.refinedAbstraction;
import com.ysj.part4.bridge.normal.abstraction.Shape;
public class Circle extends Shape {
public void draw() {
color.bepaint("圆形");
}
}
package com.ysj.part4.bridge.normal.refinedAbstraction;
import com.ysj.part4.bridge.normal.abstraction.Shape;
public class Rectangle extends Shape {
public void draw() {
color.bepaint("长方形");
}
}
package com.ysj.part4.bridge.normal.refinedAbstraction;
import com.ysj.part4.bridge.normal.abstraction.Shape;
public class Square extends Shape {
public void draw() {
color.bepaint("正方形");
}
}
实现:颜色,定义方法着色bepaint()
package com.ysj.part4.bridge.normal.implementor;
public interface Color {
public void bepaint(String shape);
}
具体实现:黑色、灰色、白色,重写bepaint()
package com.ysj.part4.bridge.normal.concreteImplementor;
import com.ysj.part4.bridge.normal.implementor.Color;
public class Black implements Color {
public void bepaint(String shape) {
System.out.println("黑色的" + shape);
}
}
package com.ysj.part4.bridge.normal.concreteImplementor;
import com.ysj.part4.bridge.normal.implementor.Color;
public class Gray implements Color {
public void bepaint(String shape) {
System.out.println("灰色的" + shape);
}
}
package com.ysj.part4.bridge.normal.concreteImplementor;
import com.ysj.part4.bridge.normal.implementor.Color;
public class White implements Color {
public void bepaint(String shape) {
System.out.println("白色的" + shape);
}
}
客户端:绘图者
package com.ysj.part4.bridge.normal;
import com.ysj.part4.bridge.normal.abstraction.Shape;
import com.ysj.part4.bridge.normal.concreteImplementor.Gray;
import com.ysj.part4.bridge.normal.concreteImplementor.White;
import com.ysj.part4.bridge.normal.refinedAbstraction.Circle;
import com.ysj.part4.bridge.normal.refinedAbstraction.Rectangle;
import com.ysj.part4.bridge.normal.refinedAbstraction.Square;
/**
* 桥接模式
* 将抽象部分与它的实现部分分离,使它们都可以独立地变化
*/
public class Client {
public static void main(String[] args) {
// 绘制白色的正方形
Shape square = new Square().setColor(new White());
square.draw();
// 绘制灰色的圆形
Shape rectange = new Circle().setColor(new Gray());
rectange.draw();
}
}
已知应用
Java AWT/Swing库:
Java AWT 和 Swing 是 Java 的图形用户界面库。在 Swing 中,JComponent 类继承自 Container 类,而 Container 类又实现了 AWTComponent 接口。这样,Swing 组件可以通过 AWT 的底层实现来绘制自己,实现了外观与行为的分离。
评论区