引言
在实际的业务中,经常会遇到多维度的概念组合,公园的门票,颐和园有年票、月票、日票,故宫也有年票、月票、日票。那么不同的公园和票种类型就可以视为两种不同的纬度,它们之间会形成相互组合的关系。
在类的设计上,如果任由两种纬度的类任意组合的话,那么就会形成笛卡尔积的情况,使类泛滥,难以维护。
在设计模式中,桥接模式就是为了解决这个问题而提出的,它通过将两种或多种纬度以上层抽象的组合关系为基础,形成一种桥接模型,将业务的组合时机延迟到客户端调用使才发生,避免在编写类的时候,大量的枚举每一种具体情况。
一、待解决问题描述
类似上面公园和票种的纬度关系,这里提出一种简单的案例:形状和颜色。
假设我们需要两种不同的形状——圆形、正方形,和两种不同的颜色——红色、白色,并将它们组合以产生特定的类型,那么我们就需要四种不同:
这种做法虽然简单直观,但也大大增加了类的数量,而且两个维度的概念耦合性太强,如果增加了新的纬度,那么类的规模将成倍增长。
二、桥接模式类图
在学习桥接模式的时候,不仅应该掌握最主要的纬度的划分与如何实现桥接,还应该思考桥接模式之外的内容,比如上面的例子中,我们可以很清晰的划分出形状和颜色两个维度,同时下面的类图也展示了通过怎样的编码技巧实现桥接的解耦。还有一点之外的内容就是,我们应该以哪种维度作为主干?为什么接入主干维度的其他维度要采用接口?而主干维度采用抽象类?
上图中,Shape是一个抽象类,这是对主干维度——形状的一个抽象,其实现类有Circle、Square,它们代表了一种具体的形状。
Color是一个接口,Red、White代表两种不同的具体的颜色。
在这个例子中,Color 和 Shape 相比,很显然Shape更像是一种主体纬度,而颜色,更适合作为一种附属属性依附于主体纬度,在这个例子中 Color 仅仅提供了一种行为,所以直接使用接口来描述,这当然不是必须的。
Color 与 Shape 的关系是聚合,采用的是 set 方法注入到 Shape 中,这需要根据具体的业务来判断两种纬度的依赖关系,聚合的耦合度更低,且更灵活,可以只在必要的时候将两种纬度聚合在一起。而组合可能在构造时就需要传入属性,这需要视具体情况而定。
三、桥接模式的具体实现
/*** 主干维度————形状*/
public abstract class Shape {protected Color color;public void setColor(Color color) {this.color = color;}public abstract void draw();
}
/*** 颜色维度*/
public interface Color {void paint(String shape);
}
public class Circle extends Shape {@Overridepublic void draw() {color.paint("圆形");}
}
public class Square extends Shape {@Overridepublic void draw() {color.paint("正方形");}
}
public class Red implements Color {@Overridepublic void paint(String shape) {System.out.println("红色的" + shape);}
}
public class White implements Color {@Overridepublic void paint(String shape) {System.out.println("白色的" + shape);}
}
以上是桥接模式中的几个重要角色,以下是测试代码:
public class Client {public static void main(String[] args) {Shape square = new Square();square.setColor(new Red());square.draw();square.setColor(new White());square.draw();System.out.println("==============");Shape circle = new Circle();circle.setColor(new Red());circle.draw();circle.setColor(new White());circle.draw();}
}
输出结果:
红色的正方形
白色的正方形
==============
红色的圆形
白色的圆形
总结
桥接模式基于类的最小设计原则,其中包括几个重要的角色:
1、Client,客户端
2、Abstraction,抽象类
3、Refined Abstraction ,扩展抽象类
4、Implementor,行为实现类接口
5、ConcreteImplementor, 具体的行为实现
桥接模式标准类图如下:
桥接模式有以下几点好处:
1、实现了抽象与行为的分离
2、更好的扩展性
3、可动态切换实现
4、实现细节对客户端透明,可以对用户隐藏实现细节
缺点也有几点:
1、增加了系统的理解难度和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
2、桥接模式要求正确识别出系统中的两个独立变化的纬度,因此使用范围具有一定的局限性。