您现在的位置是:首页 >其他 >设计模式之桥接模式释义与举例剖析网站首页其他
设计模式之桥接模式释义与举例剖析
一、前言
开始学Java讲继承的时候,总喜欢用一个例子来讲解,那就是画图形。这里有一个画笔,可以画正方形、长方形、圆形。除了画出指定的图形形状之外,还需要给图形进行上色。这里有三种颜色:白色
、灰色
、黑色
。我们可以画出9
种图形,白色正方形、白色长方形、白色圆形
…。
好,我们开始动手了,老师说要求画出圆形、正方形
,并给他们涂上蓝色、红色
,分别是红色圆形
、红色正方形
、蓝色圆形
、蓝色正方形
。
老师看了看你提交的作业,非常的满意。之后突发奇想,在加上青色,灰色,绿色
的颜色。形状在加上``长方形,三角形。这样一想,还要建立20个类。
抛开设计模式不说:如果是日常生活中,我们会如何处理这种情况。一般会将所有的情况都放到两个集合中,你需要什么我就去两个集合中取出对应的属性。
很明显可以看出来,对于这个问题有两个个变化的维度,分别是形状和颜色。对于这种有多个变化纬度的组合问题,一般采用上述的第二种方式,这样除了减少系统中的类个数,也利于系统扩展。对于方案二的应用我们称之为桥接模式。
二、模式定义
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。
桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。
这里的抽象部分与实现部分分离开?
不是将抽象类与他的派生类分离,而是抽象类和它的派生类用来实现自己的对象。这句话可能还不是很好理解,按照上面的例子来说明,实现系统可能有多个角度分类,如上中,颜色和形状在不断的变化,以前是直接利用图形的抽象,图形的实现,然后给每个图形进行painting
。
现在就是,将图形的抽象和图形的实现分离开来,让**多角度分类(颜色,形状)**分离,让他们独立变化,减少他们的耦合。
要理解桥接模式,重点需要理解如何将抽象化(Abstraction
)与实现化(Implementation
)脱耦,使得二者可以独立地变化。
- 抽象化:抽象化就是忽略一些信息,把不同的实体当作同样的实体对待。在面向对象中,将对象的共同性质抽取出来形成类的过程即为抽象化的过程。
- 实现化:针对抽象化给出的具体实现,就是实现化,抽象化与实现化是一对互逆的概念,实现化产生的对象比抽象化更具体,是对抽象化事物的进一步具体化的产物。
- 脱耦:脱耦就是将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联,将两个角色之间的继承关系改为关联关系。桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。
三、模式结构
桥接模式包含如下角色:
Abstraction
:抽象类RefinedAbstraction
:扩充抽象类Implementor
:实现类接口ConcreteImplementor
:具体实现类
四、案例具体实现
对于上图中,利用上述画画的例子一一进行对照。
tips: 当然,也可以将color作为
Abstraction
抽象类,是一样去实现的,下面只是提供一种实现方法。
按照第一次举的例子:Abstraction
就是Shape
public abstract class Shape {
abstract void draw(); // opertion()
Color color;
public void setColor(Color color){
this.color = color;
}
}
而对于RefinedAbstraction
,扩充抽象类,这里不一定就是抽象类,也可以是具体的实现类。这里我直接让各种形状
继承Shape
。
public class Circle extends Shape{
@Override
void draw() {
color.bepaint("圆形");
}
}
public class Rectangle extends Shape{
@Override
public void draw() {
color.bepaint("长方形");
}
}
public class Square extends Shape{
@Override
void draw() {
color.bepaint("正方形");
}
}
对于Implementor
:实现类接口,这里我定义的是颜色。
public interface Color {
// 画颜色
void bepaint(String shape);
}
ConcreteImplementor
:具体实现类
public class Black implements Color{
@Override
public void bepaint(String shape) {
System.out.println("黑色的" + shape);
}
}
public class Gray implements Color{
@Override
public void bepaint(String shape) {
System.out.println("灰色的" + shape);
}
}
public class White implements Color{
@Override
public void bepaint(String shape) {
System.out.println("白色的" + shape);
}
}
对于client
public class Client {
public static void main(String[] args) {
// 创建第一个类
Color white = new White();
// 正方形
com.fckey.design.bridge.Square squareBridge = new com.fckey.design.bridge.Square();
// 白色的正方形
squareBridge.setColor(white);
squareBridge.draw();
// 圆形
com.fckey.design.bridge.Circle circle = new com.fckey.design.bridge.Circle();
circle.setColor(white);
circle.draw();
}
}
对于Client
使用组合对象时的时序图
五、 模式优缺点
-
优点
1、分离抽象接口及其实现部分。提高了比继承更好的解决方案。
2、桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
3、实现细节对客户透明,可以对用户隐藏实现细节。 -
缺点
1、桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
2、桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
六、 模式使用场景
1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
七、 模式总结
对于桥接模式,我认为最大的作用就是能够防止类爆炸问题,将继承转变为组合的方式,可以对系统进行解耦。对于桥接模式
通常是预先设计的,让您可以独立开发应用程序的各个部分。另一方面,适配器模式
通常与现有应用程序一起使用,以使一些原本不兼容的类可以很好地协同工作。
桥接、状态、策略(在某种程度上还有适配器)具有非常相似的结构
。实际上,所有这些模式都基于组合,即将工作委托给其他对象。然而,它们都解决了不同的问题。模式不仅仅是以特定方式构建代码的秘诀。它还可以与其他开发人员交流该模式解决的问题。
您可以将Abstract Factory
与Bridge
一起使用。当Bridge
定义的某些抽象只能用于特定实现时,这种配对很有用。在这种情况下,抽象工厂可以封装这些关系并向客户端代码隐藏复杂性。
还可以将 Builder
与Bridge
结合使用:director 类
扮演抽象的角色,而不同的构建器充当实现。
本博文设计到的完整代码 : GitHub 完整代码
参考
桥接模式最核心的思想
design-patterns bridge
桥接设计模式,有效的减少类爆炸!
桥接模式优缺点
菜鸟教程/桥接模式