一、结构型模式

在面向对象的世界里,如何优雅地组织类与对象、构建更大的结构,是每一位开发者都会反复思考的问题。直接堆砌类和继承固然简单,但当业务复杂度上升、类间关系变得盘根错节时,这种方式就会让代码变得臃肿、难以维护。

结构型设计模式正是为了解决这一痛点而诞生的一套思想体系。它们关注如何将类或对象按某种布局组合成更大的结构,通过组合、代理、适配和装饰等手段,让代码更具灵活性、可复用性和可维护性。

在 Java 开发中,结构型模式主要包含以下 7 种经典实现:

  1. 代理模式 (Proxy):为其他对象提供一种代理以控制对这个对象的访问,实现延迟加载、权限控制等。Java 设计模式・代理模式篇:从思想到代码实现-CSDN博客
  2. 适配器模式 (Adapter):将一个类的接口转换成客户期望的另一个接口,让原本不兼容的类可以协同工作。Java 设计模式・适配器模式篇:从思想到代码实现-CSDN博客
  3. 装饰器模式 (Decorator):动态地给一个对象添加额外的职责,比生成子类更灵活地扩展功能。Java 设计模式・装饰器模式篇:从思想到代码实现-CSDN博客
  4. 桥接模式 (Bridge):将抽象部分与它的实现部分分离,使它们都可以独立地变化,避免类爆炸。
  5. 外观模式 (Facade):为子系统中的一组接口提供一个统一的高层接口,使子系统更容易使用。Java 设计模式・外观模式篇:从思想到代码实现-CSDN博客
  6. 组合模式 (Composite):将对象组合成树形结构以表示 “部分 - 整体” 的层次关系,使客户端对单个对象和组合对象的使用具有一致性。Java 设计模式・组合模式篇:从思想到代码实现-CSDN博客
  7. 享元模式 (Flyweight):运用共享技术有效地支持大量细粒度的对象,减少内存占用。​Java 设计模式・享元模式篇:从思想到代码实现-CSDN博客

二、桥接模式

2.1 介绍

桥接模式是一种结构型设计模式,它将抽象部分它的实现部分分离,使它们都可以独立地变化。这里的 “抽象部分” 指业务概念的高层抽象(如图形),“实现部分” 指具体的底层实现(如颜色),通过 “桥”(抽象类持有实现类的引用)让两者解耦、独立扩展。用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度

2.2 角色

  • 抽象化(Abstraction)角色 :定义抽象类,并包含一个对实现化对象的引用。

  • 扩展抽象化(Refined Abstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。

  • 实现化(Implementor)角色 :定义实现化角色的接口,供扩展抽象化角色调用。

  • 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

三、代码实现

本文为了方便理解,使用中文类名

3.1 实现化角色

public interface 颜料 {
    void getColor();
}

3.2 具体实现化角色

public class 红色颜料 implements 颜料{
    @Override
    public void getColor() {
        System.out.println("涂上红色颜料");
    }
}
public class 黄色颜料 implements 颜料{
    @Override
    public void getColor() {
        System.out.println("涂上黄色颜料");
    }
}

3.3 抽象化角色

public abstract class 绘画工具 {
    protected 颜料 color;

    public 绘画工具(颜料 color) {
        this.color = color;
    }

    public abstract void draw();
}

3.4 扩展抽象化角色

public class 毛笔 extends 绘画工具{

    public 毛笔(颜料 color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("用毛笔开始绘制...");
        color.getColor();
    }
}
public class 刷子 extends 绘画工具{

    public 刷子(颜料 color) {
        super(color);
    }

    @Override
    public void draw() {
        System.out.println("用刷子开始绘制...");
        color.getColor();
    }
}

3.5 客户端

public class 客户端 {
    public static void main(String[] args) {
        绘画工具 drawTool1 = new 刷子(new 黄色颜料());
        drawTool1.draw();
        绘画工具 drawTool2 = new 毛笔(new 红色颜料());
        drawTool2.draw();
    }
}
用刷子开始绘制...
涂上黄色颜料
用毛笔开始绘制...
涂上红色颜料

Process finished with exit code 0

四、优缺点

4.1 优点

  • 彻底解耦抽象与实现,避免排列组合导致类爆炸
  • 符合 “开闭原则”,扩展极其灵活 , 新增维度时无需修改原有代码,只需要新增类即可

  • 提高代码复用性,抽象层和实现层的逻辑可以各自复用

4.2 缺点

缺点主要体现在 “复杂度” 和 “学习成本” 上,适合复杂场景,简单场景会 “过度设计”

五、使用场景

  • 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。

  • 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。

  • 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。

六、对比

6.1 对比装饰者模式

Java 设计模式・装饰器模式篇:从思想到代码实现-CSDN博客

都属于结构型模式,都能实现功能扩展,都避免了类爆炸。

维度 桥接模式 装饰者模式
解决的问题 解耦两个独立变化的维度 单一对象动态添加功能(比如给毛笔加 “防水”“加粗” 功能)
核心逻辑 抽象层持有实现层引用(桥接),维度独立扩展 包装原对象,层层嵌套增强功能
设计目的 分离 “抽象” 和 “实现”,提前规划多维度扩展 动态增强对象功能,运行时灵活调整

6.2 对比适配器模式

Java 设计模式・适配器模式篇:从思想到代码实现-CSDN博客

都有 “连接” 的思想,都能让两个部分协同工作。

维度 桥接模式 适配器模式
解决的问题 解耦两个独立变化的维度,让它们原生适配(颜料和工具天生就匹配) 解决接口不兼容问题,让原本不匹配的两个类能一起工作
设计时机 设计初期就规划好,主动拆分维度 设计后期 / 集成第三方代码时,被动适配
核心逻辑 抽象层依赖实现层接口(面向接口编程) 封装原有接口,转换为目标接口

6.3 对比继承

都能实现功能复用和扩展。

维度 桥接模式 继承
扩展方式 组合(抽象类持有实现类引用) 继承(子类继承父类)
灵活性 运行时可切换实现(比如毛笔换颜料) 编译时确定,无法动态切换
类数量 线性增长(新增颜料 / 工具各加 1 类) 指数增长(类爆炸,比如红毛笔、黑毛笔、红刷子…)
耦合度 低(抽象和实现解耦) 高(子类依赖父类,父类修改影响子类)

七、源码举例: logging

7.1 实现化角色

public abstract class Handler {
    ...

    public abstract void publish(LogRecord record);

    ...
}

7.2 具体实现化角色

public class ConsoleHandler extends StreamHandler {
    ...

    @Override
    public void publish(LogRecord record) {
        super.publish(record);
        flush();
    }

    ...
}

public class StreamHandler extends Handler {
    ...
}

7.3 抽象化角色

public class Logger {
    private static final Handler emptyHandlers[] = new Handler[0];

    ...

    private static final class ConfigurationData {
        ...

        void addHandler(Handler h) {
            if (handlers.add(h)) {
                if (delegate != this) {
                    // merge in progress - propagate value to system peer.
                    final ConfigurationData system = delegate;
                    synchronized (system) {
                        system.handlers.addIfAbsent(h);
                    }
                }
            }
        }

        ...
    }
    
    ...
}

7.4 扩展抽象化角色

java.util.logging 中,Logger 本身已是具体类(非抽象),因此 “扩展抽象化” 角色体现在通过 Logger.getLogger() 获取的具体日志器实例(比如业务模块专属的 Logger)

八、其他相关设计模式

Java 设计模式・总结目录篇:从思想到代码实现-CSDN博客

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐