桥接模式定义
桥接模式是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interfce)模式。
在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。 [1]
意图编辑
【GOF95】在提出桥梁模式的时候指出,桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。这句话有三个关键词,也就是抽象化、实现化和脱耦。
抽象化
存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待。
实现化
抽象化给出的具体实现,就是实现化。
脱 耦
所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。
将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥梁模式的用意。
结构
可以看出,这个系统含有两个等级结构,也就是:
- 由抽象化角色和修正抽象化角色组成的抽象化等级结构。
- 由实现化角色和两个具体实现化角色所组成的实现化等级结构。
桥梁模式所涉及的角色有:
- 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
- 修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
- 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
- 具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。
桥接模式通用类图如下:
首先定义Implementor接口,其中定义了其实现类必须要实现的接口operation()
package com.ssy.wlj.bridge; /** * Implementor接口 * @author Administrator * @since 2019/05/23 * */ public interface Implementor { public void operation(); }
下面定义Implementor接口的两个实现类:
package com.ssy.wlj.bridge; public class ConcreateImplementorA implements Implementor { @Override public void operation() { System.out.println("this is concreteImplementorA's operation..."); } }
package com.ssy.wlj.bridge; public class ConcreateImplementorB implements Implementor { @Override public void operation() { System.out.println("this is concreteImplementorB's operation..."); } }
下面定义桥接类Abstraction,其中有对Implementor接口的引用:
package com.ssy.wlj.bridge; public class Abstraction { private Implementor implementor; public Implementor getImplementor() { return implementor; } public void setImplementor(Implementor implementor) { this.implementor = implementor; } protected void operation() { implementor.operation(); } }
下面是Abstraction类的子类RefinedAbstraction:
package com.ssy.wlj.bridge; public class RefinedAbstraction extends Abstraction { @Override protected void operation() { super.getImplementor().operation(); } }
测试类:
package com.ssy.wlj.bridge; public class BridgeTest { public static void main(String[] args) { Abstraction abstraction = new RefinedAbstraction(); // 调用第一个实现类 abstraction.setImplementor(new ConcreateImplementorA()); abstraction.operation(); // 调用第二个实现类 abstraction.setImplementor(new ConcreateImplementorB()); abstraction.operation(); } }
测试结果:
this is concreteImplementorA's operation... this is concreteImplementorB's operation...
桥接模式案例解析(二)
我们有一个作为桥接实现的 DrawAPI 接口和实现了 DrawAPI 接口的实体类 RedCircle、GreenCircle。Shape 是一个抽象类,将使用 DrawAPI 的对象。BridgePatternDemo,我们的演示类使用 Shape 类来画出不同颜色的圆。
先看类图:
第一步:创建桥接实现接口。
public interface DrawAPI { public void drawCircle(int radius, int x, int y); }
第二步:创建实现了 DrawAPI 接口的实体桥接实现类。
public class RedCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { System.out.println("Drawing Circle[ color: red, radius: " + radius +", x: " +x+", "+ y +"]"); } }
public class GreenCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { System.out.println("Drawing Circle[ color: green, radius: " + radius +", x: " +x+", "+ y +"]"); } }
第三步:使用 DrawAPI 接口创建抽象类 Shape。
public abstract class Shape { protected DrawAPI drawAPI; protected Shape(DrawAPI drawAPI){ this.drawAPI = drawAPI; } public abstract void draw(); }
第四步:创建实现了 Shape 接口的实体类。
public class Circle extends Shape { private int x, y, radius; public Circle(int x, int y, int radius, DrawAPI drawAPI) { super(drawAPI); this.x = x; this.y = y; this.radius = radius; } public void draw() { drawAPI.drawCircle(radius,x,y); } }
第五步:使用 Shape 和 DrawAPI 类画出不同颜色的圆。
public class Client { public static void main(String[] args) { Shape redCircle = new Circle(100,100, 10, new RedCircle()); Shape greenCircle = new Circle(100,100, 10, new GreenCircle()); redCircle.draw(); greenCircle.draw(); } }
第六步:执行程序,输出结果:
Drawing Circle[ color: red, radius: 10, x: 100, 100]
Drawing Circle[ color: green, radius: 10, x: 100, 100]
总结:
1.桥接模式的优点
- (1)实现了抽象和实现部分的分离
- 桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
- (2)更好的可扩展性
- 由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。
- (3)可动态的切换实现
- 由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。
- (4)实现细节对客户端透明,可以对用户隐藏实现细节。
2.桥接模式的缺点
- (1)桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
- (2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。
3.桥接模式的使用场景
- (1)如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- (2)抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
- (3)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
- (4)虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
- (5)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用