JavaScript设计模式「基于ES2024」:结构型模式-桥接模式

70 阅读2分钟

桥接模式能将抽象部分与实现部分分离,使它们都可以独立地变化。这种模式对于处理跨平台应用、支持多种类型的数据库服务或处理不同类型的用户界面控件特别有用。

// 实现部分的接口
class DrawingAPI {
    drawCircle(x, y, radius) {
        throw new Error('Method not implemented');
    }

    drawSquare(x, y, side) {
        throw new Error('Method not implemented');
    }
}

// 具体实现 A
class SVGDrawingAPI extends DrawingAPI {
    drawCircle(x, y, radius) {
        console.log(`Drawing Circle(${x},${y},${radius}) using SVG`);
    }

    drawSquare(x, y, side) {
        console.log(`Drawing Square(${x},${y},${side}) using SVG`);
    }
}

// 具体实现 B
class CanvasDrawingAPI extends DrawingAPI {
    drawCircle(x, y, radius) {
        console.log(`Drawing Circle(${x},${y},${radius}) using Canvas`);
    }

    drawSquare(x, y, side) {
        console.log(`Drawing Square(${x},${y},${side}) using Canvas`);
    }
}

// 抽象部分
class Shape {
    #drawingAPI;

    constructor(drawingAPI) {
        this.#drawingAPI = drawingAPI;
    }

    draw() {
        throw new Error('Method not implemented');
    }

    resize(percentage) {
        throw new Error('Method not implemented');
    }

    get drawingAPI() {
        return this.#drawingAPI;
    }
}

// 精炼抽象 A
class CircleShape extends Shape {
    #x;
    #y;
    #radius;

    constructor(x, y, radius, drawingAPI) {
        super(drawingAPI);
        this.#x = x;
        this.#y = y;
        this.#radius = radius;
    }

    draw() {
        this.drawingAPI.drawCircle(this.#x, this.#y, this.#radius);
    }

    resize(percentage) {
        this.#radius *= percentage;
    }
}

// 精炼抽象 B
class SquareShape extends Shape {
    #x;
    #y;
    #side;

    constructor(x, y, side, drawingAPI) {
        super(drawingAPI);
        this.#x = x;
        this.#y = y;
        this.#side = side;
    }

    draw() {
        this.drawingAPI.drawSquare(this.#x, this.#y, this.#side);
    }

    resize(percentage) {
        this.#side *= percentage;
    }
}

// 使用示例
function clientCode() {
    const shapes = [
        new CircleShape(1, 2, 3, new SVGDrawingAPI()),
        new SquareShape(5, 7, 4, new CanvasDrawingAPI()),
        new CircleShape(5, 7, 11, new CanvasDrawingAPI()),
        new SquareShape(2, 2, 8, new SVGDrawingAPI())
    ];

    shapes.forEach(shape => {
        shape.draw();
        shape.resize(2);
        shape.draw();
    });
}

clientCode();

实现思路

  1. DrawingAPI:这是实现部分的接口,定义了绘制不同形状的方法。
  2. SVGDrawingAPICanvasDrawingAPI:这些是具体的实现类,分别使用 SVG 和 Canvas 技术来绘制形状。
  3. Shape:这是抽象部分的基类,它包含一个对 DrawingAPI 的引用。
  4. CircleShapeSquareShape:这些是精炼的抽象类,它们继承自 Shape 并实现了具体的绘制和调整大小的逻辑。
  5. 使用私有字段(如 #drawingAPI, #x, #y 等)来增强封装性。
  6. clientCode 函数:展示了如何使用不同的形状和绘图 API 的组合。

优点

  • 解耦抽象和实现:抽象(形状)和实现(绘图 API)可以独立变化,不会相互影响。
  • 提高可扩展性:可以轻松添加新的形状或新的绘图 API,而不会影响现有代码。
  • 隐藏实现细节:客户端代码只需要知道抽象接口,不需要了解具体实现。
  • 运行时切换实现:可以在运行时动态切换不同的实现。