《设计模式》第九篇:三大类型之结构型模式
结构型模式(Structural Pattern)关注如何将类或对象组合在一起形成更大的结构,让它们既能保持独立性,又能协同工作。
结构型模式主要解决的是“如何组合对象/类”的问题,核心目标是:
- 提高系统的灵活性
- 降低耦合度
- 让已有类/对象能被复用或适配
GoF 经典的 7 种结构型模式如下:
- 适配器模式(Adapter)
- 桥接模式(Bridge)
- 组合模式(Composite)
- 装饰器模式(Decorator)
- 外观模式(Facade)
- 享元模式(Flyweight)
- 代理模式(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 源码的对应,或者想看结构型模式面试高频题,可以告诉我,我继续展开。