《设计模式》第九篇:三大类型之结构型模式

《设计模式》第九篇:三大类型之结构型模式

结构型模式(Structural Pattern)关注如何将类或对象组合在一起形成更大的结构,让它们既能保持独立性,又能协同工作。

结构型模式主要解决的是“如何组合对象/类”的问题,核心目标是:

  • 提高系统的灵活性
  • 降低耦合度
  • 让已有类/对象能被复用适配

GoF 经典的 7 种结构型模式如下:

  1. 适配器模式(Adapter)
  2. 桥接模式(Bridge)
  3. 组合模式(Composite)
  4. 装饰器模式(Decorator)
  5. 外观模式(Facade)
  6. 享元模式(Flyweight)
  7. 代理模式(Proxy)

下面逐一详细讲解,每种模式都包含:定义、意图、核心结构、典型代码、真实场景、优缺点

1. 适配器模式(Adapter)

定义:将一个类的接口转换成客户端期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。

意图:让两个原本不兼容的类/接口能够协同工作。

核心结构

  • 目标接口(Target)
  • 被适配者(Adaptee)
  • 适配器(Adapter)——继承或组合被适配者,实现目标接口

代码示例(对象适配器,最常用)

// 目标接口(客户端期望的)
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 被适配者(旧系统)
class VlcPlayer {
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }
}

// 适配器
class MediaAdapter implements MediaPlayer {
    private VlcPlayer vlcPlayer;

    public MediaAdapter() {
        vlcPlayer = new VlcPlayer();
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            vlcPlayer.playVlc(fileName);
        }
    }
}

// 客户端
class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            mediaAdapter = new MediaAdapter();
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Playing mp3 file. Name: " + fileName);
        }
    }
}

真实场景

  • 旧系统对接新接口
  • 第三方 SDK 适配公司内部标准接口
  • 不同支付渠道统一支付接口

2. 桥接模式(Bridge)

定义:将抽象部分与实现部分分离,使它们都可以独立变化。

意图:解决“多维度扩展”问题,避免类爆炸。

最经典例子:图形 + 颜色 + 渲染方式

// 实现部分接口
interface DrawAPI {
    void drawCircle(int radius, int x, int y);
}

// 具体实现
class RedCircle implements DrawAPI {
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing red circle [radius: " + radius + ", x: " + x + ", " + y + "]");
    }
}

// 抽象部分
abstract class Shape {
    protected DrawAPI drawAPI;
    protected Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }
    public abstract void draw();
}

class Circle extends Shape {
    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    public void draw() {
        drawAPI.drawCircle(radius, x, y);
    }
}

真实场景

  • 驱动程序(操作系统 + 显卡驱动)
  • 消息推送(渠道 + 消息类型 + 模板)
  • 支付系统(支付方式 × 支付渠道)

3. 组合模式(Composite)

定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

核心叶子节点和容器节点统一接口

abstract class Component {
    protected String name;
    public Component(String name) { this.name = name; }
    public abstract void show(int depth);
}

class Leaf extends Component {
    public Leaf(String name) { super(name); }
    public void show(int depth) {
        System.out.println("  ".repeat(depth) + "- " + name);
    }
}

class Composite extends Component {
    private List<Component> children = new ArrayList<>();

    public Composite(String name) { super(name); }

    public void add(Component c) { children.add(c); }
    public void remove(Component c) { children.remove(c); }

    public void show(int depth) {
        System.out.println("  ".repeat(depth) + "+ " + name);
        for (Component c : children) {
            c.show(depth + 1);
        }
    }
}

真实场景

  • 文件系统(文件 + 文件夹)
  • 组织架构(员工 + 部门)
  • UI 组件树(容器 + 控件)

4. 装饰器模式(Decorator)

定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器比生成子类更为灵活。

核心思想用组合代替继承,层层包裹。

abstract class Beverage {
    abstract String getDescription();
    abstract double cost();
}

class Espresso extends Beverage {
    public String getDescription() { return "Espresso"; }
    public double cost() { return 1.99; }
}

abstract class CondimentDecorator extends Beverage {
    protected Beverage beverage;
}

class Milk extends CondimentDecorator {
    public Milk(Beverage beverage) { this.beverage = beverage; }
    public String getDescription() { return beverage.getDescription() + ", Milk"; }
    public double cost() { return beverage.cost() + 0.10; }
}

真实场景

  • IO 流(BufferedInputStream 装饰 InputStream)
  • 咖啡加料(星巴克例子)
  • 权限控制、日志、缓存等切面功能

5. 外观模式(Facade)

定义:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

核心简化复杂子系统

// 复杂子系统
class CPU { public void start() {...} }
class Memory { public void load() {...} }
class HardDrive { public void read() {...} }

// 外观类
class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;

    public ComputerFacade() {
        cpu = new CPU();
        memory = new Memory();
        hardDrive = new HardDrive();
    }

    public void start() {
        cpu.start();
        memory.load();
        hardDrive.read();
        System.out.println("Computer started");
    }
}

真实场景

  • 启动电脑
  • 编译构建系统
  • 支付下单一键接口(背后调用订单、库存、支付、物流)

6. 享元模式(Flyweight)

定义:运用共享技术有效地支持大量细粒度的对象。

核心分离内部状态与外部状态,内部状态共享,外部状态独立。

class ChessPieceUnit {
    private int id;
    private String name;
    private ChessPieceUnitType type; // 内部状态,可共享
    // getter...
}

class ChessPiece {
    private ChessPieceUnit unit; // 共享
    private int positionX;       // 外部状态
    private int positionY;
}

真实场景

  • 文字处理中的字符对象(字体、颜色共享)
  • 游戏中的大量相同单位(士兵、树、石头)
  • 连接池、线程池的复用

7. 代理模式(Proxy)

定义:为其他对象提供一种代理以控制对这个对象的访问。

常见种类

  • 静态代理
  • 动态代理(JDK Proxy / CGLIB)
  • Spring AOP 本质就是代理模式

真实场景

  • 延迟加载(虚拟代理)
  • 权限控制(保护代理)
  • 日志、监控、事务(Spring AOP)
  • 远程代理(RMI、RPC)

总结:结构型模式一句话记忆

  • 适配器:让不兼容的能一起工作
  • 桥接:多维度扩展不爆炸
  • 组合:整体与部分统一对待
  • 装饰:动态添加职责
  • 外观:简化复杂子系统
  • 享元:大量相似对象共享内存
  • 代理:控制访问、增加额外功能

如果你希望继续深入某一模式的代码实现真实项目案例与 Spring 的结合与 JDK 源码的对应,或者想看结构型模式面试高频题,可以告诉我,我继续展开。

文章已创建 4580

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部