桥梁设计模式

桥梁设计模式

桥梁设计模式是一种结构模式,可让您将抽象与其实现解耦,从而允许两者独立变化。

它在以下情况下特别有用:

您的类可以在多个正交维度上扩展(例如,形状与渲染技术、UI 控件与平台)。

您希望避免使功能组合成倍增加的深层继承层次结构 。

您需要在运行时组合行为或实现的多种变体。

桥接模式将 类拆分为两个单独的层次结构:

一个用于抽象(例如,形状、UI 控件)

一个用于实现(例如,渲染引擎、平台)

这两个层次结构通过 组合(而不是继承)"桥接",允许您独立混合和匹配。

让我们通过一个真实世界的例子来了解我们如何应用桥接模式来构建一个既灵活又可扩展的系统,而不会被埋没在刚性子类层之下。

问题:使用多个渲染后端绘制形状

想象一下,您正在构建一个跨平台图形库。它支持 使用不同的渲染方法渲染圆形和矩形等形状:

🟢 矢量渲染 -- 用于可扩展的、与分辨率无关的输出

🔵 光栅渲染 -- 用于基于像素的输出

现在,您需要支持:

绘制不同的形状(例如, CircleRectangle)

使用不同的渲染器(例如, VectorRendererRasterRenderer)

朴素实现:每个组合的子类

您可以首先创建一个如下所示的类层次结构:

复制代码
public abstract class Shape {
    protected Renderer renderer;

    public Shape(Renderer renderer) {
        this.renderer = renderer;
    }

    public abstract void draw();
}

客户端代码

复制代码
public class App {
    public static void main(String[] args) {
        Shape s1 = new VectorCircle();
        Shape s2 = new RasterRectangle();
        s1.draw(); // Drawing Circle as vEcTOoRS
        s2.draw(); // Drawing Rectangle as PIxELS
    }
}

为什么这很快就会崩溃

    1. 职业爆炸
      形状和渲染方法的每个新组合都需要一个新的子类:

2 个形状× 2 个渲染器 = 4 个类

添加第三个渲染器(例如 OpenGL)?现在你需要 6 个类

添加更多形状(例如三角形、椭圆)?组合成倍增加

这使得类层次结构臃肿和僵化。

    1. 紧密耦合
      每个类将形状逻辑和渲染逻辑联系在一起。您无法独立于形状重用渲染行为 - 它们是相互交织的。
    1. 违反开/闭原则
      如果要支持新的渲染引擎,则必须修改或重新创建该渲染器的每个形状。

我们真正需要什么

我们需要一个解决方案:

将抽象 () 与其实现分开 Shape (Renderer)

允许在不接触形状类的情况下添加新的渲染器

允许在不修改或复制渲染器逻辑的情况下添加新形状

保持系统的可扩展性、可扩展性和可组合性

这正是桥式模式的用武之地。

桥式模式

Bridge 设计模式允许您将类拆分为两个单独的层次结构------一个用于抽象,另一个用于实现------以便它们可以独立发展。

在桥接模式中,"抽象有实现"------抽象将工作委托给实现者对象。

类图

    1. 抽象(例如Shape)
      定义抽象核心行为的高级接口。它维护对 an 的引用 并将工作委托给它。Implementor
    1. RefinedAbstraction(例如, CircleRectangle)
      它的具体子类 添加了额外的行为或逻辑。它仍然依赖于实现者来执行实际执行。Abstraction
    1. 实施者(例如Renderer)
      一个接口,用于声明要由具体实现者实现的作。这些是低级作。
    1. ConcreteImplementors(例如VectorRenderer,RasterRenderer)
      实现接口的特定于平台或策略的类 。它们包含用于执行委托作的实际逻辑。Implementor

实现桥接

现在让我们实现桥接模式,将我们的形状抽象(例如,,)与渲染器实现(例如, ,)解耦。CircleRectangleVectorRendererRasterRenderer

这将使我们能够自由地混合和匹配形状和渲染引擎,而不会发生子类爆炸。

1:定义实现者接口(Renderer)

此接口声明形状的渲染作。具体实现将定义如何使用特定技术(矢量、光栅等)渲染形状。

复制代码
public interface Renderer {
    void renderCircle(float radius);
    void renderRectangle(float width, float height);
}
    1. 创建渲染器的具体实现
      这些类提供特定于平台的渲染逻辑。

🟢 矢量渲染器

复制代码
public class VectorRenderer implements Renderer {
    @Override
    public void renderCircle(float radius) {
        System.out.println("Drawing a circle of radius " + radius + " using VECTOR rendering.");
    }

    @Override
    public void renderRectangle(float width, float height) {
        System.out.println("Drawing a rectangle " + width + "x" + height + " using VECTOR rendering.");
    }
}

🔵 光栅渲染器

复制代码
public class RasterRenderer implements Renderer {
    @Override
    public void renderCircle(float radius) {
        System.out.println("Drawing pixels for a circle of radius " + radius + " (RASTER).");
    }

    @Override
    public void renderRectangle(float width, float height) {
        System.out.println("Drawing pixels for a rectangle " + width + "x" + height + " (RASTER).");
    }
}
    1. 定义抽象 (Shape)
      此类保存对渲染器的引用并定义通用 方法。draw()

    public abstract class Shape {
    protected Renderer renderer;

    复制代码
     public Shape(Renderer renderer) {
         this.renderer = renderer;
     }
    
     public abstract void draw();

    }

    1. 创建具体形状
      每个形状都将渲染委托给传递给它的渲染器。

🟠 圈

复制代码
public class Circle extends Shape {
    private final float radius;

    public Circle(Renderer renderer, float radius) {
        super(renderer);
        this.radius = radius;
    }

    @Override
    public void draw() {
        renderer.renderCircle(radius);
    }
}

🟣 矩形

复制代码
public class Rectangle extends Shape {
    private final float width;
    private final float height;

    public Rectangle(Renderer renderer, float width, float height) {
        super(renderer);
        this.width = width;
        this.height = height;
    }

    @Override
    public void draw() {
        renderer.renderRectangle(width, height);
    }
}
    1. 客户端代码
      现在,我们可以在运行时自由组合形状和渲染策略,而无需重复类。

    public class BridgeDemo {
    public static void main(String[] args) {
    Renderer vector = new VectorRenderer();
    Renderer raster = new RasterRenderer();

    复制代码
         Shape circle1 = new Circle(vector, 5);
         Shape circle2 = new Circle(raster, 5);
    
         Shape rectangle1 = new Rectangle(vector, 10, 4);
         Shape rectangle2 = new Rectangle(raster, 10, 4);
    
         circle1.draw();     // Vector
         circle2.draw();     // Raster
         rectangle1.draw();  // Vector
         rectangle2.draw();  // Raster
     }

    }

输出

复制代码
Drawing a circle of radius 5.0 using VECTOR rendering.
Drawing pixels for a circle of radius 5.0 (RASTER).
Drawing a rectangle 10.0x4.0 using VECTOR rendering.
Drawing pixels for a rectangle 10.0x4.0 (RASTER).

我们取得了什么成就

抽象与实现分离:形状和渲染器独立发展

开放/关闭合规性:您可以添加新的渲染器或形状,而无需修改现有渲染器或形状

无类爆炸:避免了对每个形状渲染器子类的需求

运行时灵活性:根据用户/设备上下文动态切换渲染器

简洁、可扩展的设计:每个类都有一个职责,可以根据需要进行组合

其他阅读材料:

复制代码
https://pan.baidu.com/s/1c1oQItiA7nZxz8Rnl3STpw?pwd=yftc
https://pan.quark.cn/s/dec9e4868381