模式动机
假设现在让你设计一个画图软件,要求是可以画出不同形状的图形,如圆形,正方形,长方形,三角形等等,同时这些图形还可以进行上色,比如红色,绿色,黄色等等,最终得到一个带有颜色的图形。此时,应该如何设计呢?首先,第一种方案是为每一种形状都提供一套各种颜色的版本,通过继承来实现,定义一个抽象图形类Shape,然后所有具体图形类如正方形(Square),圆形(Circle)继承于Shape,然后继续继承,定义出各种带颜色的图形如RedSquare,GreenSquare,RedCircle,GreenCircle等等。结构如下图:
以上确实是一种解决方案,但试想一下,如果我们有m种图形,有n种颜色,那我们将便会有m×n个子类,毫无疑问,这样的设计比较欠妥。此时,对于这种有两个维度变化的情况,我们应当考虑桥接模式。
模式定义
将抽象部分与它的实现部分分离,使它们都可以独立地变化。桥接模式将继承关系转换为关联关系,从而降低类与类之间的耦合,减少了代码量。
对于上面的那种情况,我们可以把图形和颜色剥离成两个维度,根据实际需要对形状和颜色这两个维度进行组合,这样不仅可以大大减少代码量,而且还可以相互独立,提高可扩展性和可维护性。如下图:
模式结构
抽象类:Abstraction
扩展实现类:RefinedAbstraction
实现类接口:Implementor
具体实现类: ConcreteImplementor
代码示例
下面通过代码来看看桥接模式的具体实现。
//颜色接口,相当于模式结构中的Implementor
public interface Color {
public abstract String paint();
}
//具体颜色类-绿色,相当于模式结构图中的ConcreteImplementor
public class Green implements Color{
@Override
public String paint() {
return "绿色";
}
}
//具体颜色类-红色,相当于模式结构图中的ConcreteImplementor
public class Red implements Color{
@Override
public String paint() {
return "红色";
}
}
//抽象形状类,相当于模式结构图中的Abstraction
public abstract class Shape {
protected Color color;
public void setColor(Color color){
this.color = color;
}
public abstract void draw();
}
//具体形状类-圆形,相当于模式结构中的RefinedAbstraction
public class Circle extends Shape{
@Override
public void draw() {
System.out.println(this.color.paint() + "圆形");
}
}
//具体形状类-正方形,相当于模式结构中的RefinedAbstraction
public class Square extends Shape{
@Override
public void draw() {
System.out.println(this.color.paint() + "正方形");
}
}
/客户端
public class Client {
public static void main(String[] args) {
Color green = new Green();
Color red = new Red();
Shape square = new Square();
Shape circle = new Circle();
square.setColor(green);
square.draw();//绿色正方形
square.setColor(red);
square.draw();//红色正方形
circle.setColor(green);
circle.draw();//绿色圆形
circle.setColor(red);
circle.draw();//红色圆形
}
}
可以看到,使用桥接模式大大减少了代码量。主要是因为这里使用的是组合关系,把Color作为Shape的一部分,而不是第一种设计方案中的继承。桥接模式的精髓就在于降低抽象化与实现化耦合关系,在抽象化和实现化之间使用关联关系(组合或者聚合)而不是继承关系,从而使两者可以相对独立。