定义
将抽象部分与实现部分分离开来,使得二者可以独立变化,互不影响的结构型设计模式。
主要组成
抽象部分(Abstraction) :
该类保持一个对实现部分的引用,抽象部分中的方法需要调用实现部分的对象的方法来实现;这部分一般为抽象类居多。
具体抽象部分(Concrete Abstraction):
抽象部分的具体实现,一般用于抽象部分方法的完善和扩展;
实现部分(Implementor) :
可以为接口或抽象类,其方法不一定要与抽象部分中的一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分这些基本操作的业务方法;
具体实现部分(Concrete Implementor):
实现完善"实现部分"定义的相关接口功能;
客户端(Client):
客户类,客户端程序 (调用程序的地方)
具体例子
实现部分(Implementor) : Line"线",抽象为接口类,方法为Draw"画线"。
具体实现部分(Concrete Implementor): 实现Line功能的子类,例如SolidLine绘制实线、DottedLine绘制虚线。
抽象部分(Abstraction): 形状Shape,持有一个Implementor的引用,并定义出需要借助Implementor来实现的方法,比如使用“线"绘制出形状
具体抽象部分(Concrete Abstraction): Abstraction的实现类,完善扩展Implementor的方法。比如三角形、矩形、圆形等,绘制出各自的图形
可以看到Implementor和Abstraction有相对明显的上下级,Abstraction需要调用Implementor来实现目的,是Implementor上级。
UML图
image框架代码
实现部分(Implementor):
public interface Line {
void draw();
}
具体实现部分(Concrete Implementor):
public class SolidLine implements Line {
@Override
public void draw() {
//...
System.out.println("绘制实线");
}
}
public class GottedLine implements Line {
@Override
public void draw() {
//...
System.out.println("绘制虚线");
}
}
抽象部分(Abstraction):
public abstract class Shape {
//持有一个实现部分Implementor引用
Line line;
public Shape(Line line) {
this.line = line;
}
public abstract void drawShape();
}
具体抽象部分(Concrete Abstraction):
public class Circular extends Shape {
public Circular(Line line) {
super(line);
}
@Override
public void drawShape() {
//...
line.draw();
System.out.println("绘制出圆形");
//...
}
}
public class Rectangle extends Shape {
public Rectangle(Line line) {
super(line);
}
@Override
public void drawShape() {
//...
line.draw();
System.out.println("绘制出矩形");
//...
}
}
客户端调用示例:
//使用实线绘制圆形
Circular solidCircular = new Circular(new SolidLine());
solidCircular.drawShape();
//使用虚线绘制圆形
Circular gottedCircular = new Circular(new GottedLine());
gottedCircular.drawShape();
//使用实线绘制矩形
Rectangle solidRectangle = new Rectangle(new SolidLine());
solidRectangle.drawShape();
//使用虚线绘制矩形
Rectangle gottedRectangle = new Rectangle(new GottedLine());
gottedRectangle.drawShape();
假设不使用桥接模式
上述例子假设没使用桥接模式,很明显会出现"类爆炸"的问题,类数量出现快速增加:
image假设目前只有m=3种线: 实线、虚线、双实线,需要绘制的形状为n=2种:圆形、矩形。
那么当实现的类个数为m * n ,以后无论多增加一种形状(增加m个线数量的实现类),或者多增加一种线(增加n个形状的实现类),(在基数足够大的情况下)都会爆炸式的增加太多的实现类。
而如果如上使用桥接模式,无论是增加形状(抽象部分)、线(实现部分),理论上都只需要增加各自的一个具体实现,实现了抽象部分和实现部分可以独立修改互不影响。
总结
桥接模式一般用于存在上下级关系的二维变化系统中,将底层的部分分割为实现层,将较上层的部分分割为抽象层。
抽象层中的方法实现实际依赖于实现层对象的方法。
优点
分离抽象和实现部分:
桥接模式分离了抽象和实现部分,从而极大地提高了系统的灵活性。让抽象部分和实现部分独立开来,分别定义接口,这有助于对系统进行分层,从而产生更好的结构化的系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
灵活的扩展性:
由于桥接模式把抽象和实现部分分离开了,而且分别定义接口,这就使得抽象部分和实现部分可以分别独立的扩展,而不会相互影响,从而大大的提高了系统的可扩展性。可动态切换实现。
由于桥接模式把抽象和实现部分分离开了,那么在实现桥接的时候,就可以实现动态的选择和使用具体的实现,也就是说一个实现不再是固定的绑定在一个抽象接口上了,可以实现运行期间动态的切换实现。
缺点
实际应用中相对不容易设计,因为判断哪部分作为实现部分,哪部分作为抽象部分对开发者要有一定的经验要求。
使用场景
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,可以通过桥接模式使他们在抽象层建立一个关联关系。
对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,也可以考虑使用桥接模式。
一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
思考:
1.桥接模式可以做到的感觉装饰者模式好像也可以做到,二者的区别?
装饰者模式支持使用多个装饰者多次装饰被装饰者,并且要求装饰者和被装饰者提供一致的接口行为,接口要求返回的也是统一的被装饰者接口对象。
而桥接模式一般用一个抽象部分来扩展完善实现部分,并不要求提供一致的接口行为。
装饰者模式一般没有明显的上下级依赖关系,但是桥接模式的2个维度往往会有上下级依赖关系的存在。
2.怎么判断哪部分作为实现部分,哪部分作为抽象部分?
一般是真正的"实现"部分(被依赖的部分)作为实现部分,上层作为抽象部分,可以从例子中理会,因为要绘制形状需要依赖于绘制线,绘制线其实是真正的实现部分,绘制形状只是把绘制的线进行拼接(扩展完善了线的功能作用,封装业务功能等)。所以线是实现部分,形状是抽象部分。
网友评论