结构型-桥接模式 Link to heading

桥接模式是将抽象部分与它的实现部分分离,使它们都可以独立地变化。

【GOF95】在提出桥梁模式的时候指出,桥梁模式的用意是"将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。这句话有三个关键词,也就是抽象化、实现化和脱耦。

下列各语言的代码都用于写出两个不同的圆的坐标和半径。

/** "Implementor" */
interface DrawingAPI{
  public void drawCircle(double x, double y, double radius);
}
/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI{
  public void drawCircle(double x, double y, double radius){  
    System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);   
  }
}
/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI{
  public void drawCircle(double x, double y, double radius){        
    System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
  }
}/** "Abstraction" */
interface Shape{
  public void draw();                             // low-level
  public void resizeByPercentage(double pct);     // high-level
}
/** "Refined Abstraction" */
class CircleShape implements Shape{
  private double x, y, radius;
  private DrawingAPI drawingAPI;
  public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI){   
    this.x = x;  this.y = y;  this.radius = radius;
    this.drawingAPI = drawingAPI;
  }   
  // low-level i.e. Implementation specific
  public void draw(){
    drawingAPI.drawCircle(x, y, radius);
  }      
  // high-level i.e. Abstraction specific   
  public void resizeByPercentage(double pct){ 
    radius *= pct;
  }
}

/** "Client" */
class BridgePattern{
  public static void main(String[] args){
    Shape[] shapes = new Shape[2];
    shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
    shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());
    for (Shape shape : shapes){
      shape.resizeByPercentage(2.5);
      shape.draw();
    }
  }
}

场景模拟 Link to heading

在购买奶茶的时候,店员首先会问我们,您需要什么类型的奶茶,比如我们此时点了一杯啵啵芋圆奶茶,接着店员会直接问我们需要大杯、中杯还是小杯,最后还会询问我们需要加什么配料,比如椰果、珍珠等,最后才会给我们制作奶茶。

最初设计 Link to heading

public interface Tea {   //由具体类型的奶茶实现
    String getType();   //不同的奶茶返回的类型不同
}

public interface Size {   //分大杯小杯中杯
    String getSize();
}

/**
 * 大杯芋圆啵啵奶茶
 */
public class LargeKissTea implements Tea, Size{

    @Override
    public String getSize() {
        return "大杯";
    }

    @Override
    public String getType() {
        return "芋圆啵啵奶茶";
    }
}

现在一共有两个维度需要考虑,那么我们岂不是得一个一个去创建这些类?甚至如果还要考虑配料,那么光创建类就得创建不知道多少个了。

改进方案 Link to heading

public abstract class AbstractTea {
    
    protected Size size;   //尺寸作为桥接属性存放在类中
    
    protected AbstractTea(Size size){   //在构造时需要知道尺寸属性
        this.size = size;
    }
    
    public abstract String getType();   //具体类型依然是由子类决定
  
      public String getSize(){   //添加尺寸维度获取方式
        return size.getSize();
    }
}

// 单独为Size创建子类
public class Large implements Size{

    @Override
    public String getSize() {
        return "大杯";
    }
}


// 芋圆波波
public class KissTea extends AbstractTea{   //创建一个啵啵芋圆奶茶的子类
    protected KissTea(Size size) {   //在构造时需要指定具体的大小实现
        super(size);
    }

    @Override
    public String getType() {
        return "啵啵芋圆奶茶";   //返回奶茶类型
    }
}

// 使用
public static void main(String[] args) {
    KissTea tea = new KissTea(new Large());
    System.out.println(tea.getType());
    System.out.println(tea.getSize());
}

通过桥接模式,使得抽象和实现可以沿着各自的维度来进行变化,不再是固定的绑定关系。