结构型模式通过适配接口、桥接抽象与实现、组合树形结构、动态装饰、简化子系统外观、共享享元及代理控制访问,优化对象间协作,提升系统灵活性与复用性。
1. 适配器模式(Adapter)
定义
将一个类的接口转换成客户端期望的另一个接口,解决接口不兼容问题。
类图
┌─────────────┐ ┌───────────────────┐
│ Target │ │ Adaptee │
├─────────────┤ ├───────────────────┤
│ +request() │ │ +specificRequest()│
└──────┬──────┘ └──────────┬────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Adapter │ │ Client │
├───────────────────┤ ├───────────────────┤
│ -adaptee: Adaptee │ │ │
│ +request() │ │ │
└───────────────────┘ └───────────────────┘
Java 实现
// 目标接口(客户端期望的接口)
interface MediaPlayer {
void play(String audioType, String fileName);
}
// 被适配的类(现有功能,但接口不兼容)
class LegacyAudioPlayer {
public void playMp3(String fileName) {
System.out.println("Playing MP3: " + fileName);
}
}
// 适配器类
class AudioAdapter implements MediaPlayer {
private LegacyAudioPlayer legacyPlayer = new LegacyAudioPlayer();
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
legacyPlayer.playMp3(fileName);
} else {
System.out.println("Unsupported format: " + audioType);
}
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
MediaPlayer player = new AudioAdapter();
player.play("mp3", "song.mp3"); // 输出: Playing MP3: song.mp3
player.play("avi", "movie.avi"); // 输出: Unsupported format: avi
}
}
适用场景
- 旧系统接口适配新系统
- 第三方库接口与项目不兼容
优缺点
- 优点:兼容性高,复用现有代码。
- 缺点:过度使用会增加系统复杂度。
2. 桥接模式(Bridge)
定义
将抽象部分与实现部分分离,使它们可以独立变化。
类图
┌───────────────────┐ ┌───────────────────┐
│ Abstraction │<>─────│ Implementor │
├───────────────────┤ ├───────────────────┤
│ +operation() │ │ +operationImpl() │
└──────┬────────────┘ └──────────┬────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ RefinedAbstraction│ │ ConcreteImplementor│
├───────────────────┤ ├───────────────────┤
│ +operation() │ │ +operationImpl() │
└───────────────────┘ └───────────────────┘
Java 实现
// 实现部分接口
interface Renderer {
void renderShape(String shape);
}
// 具体实现:矢量渲染
class VectorRenderer implements Renderer {
@Override
public void renderShape(String shape) {
System.out.println("Drawing " + shape + " as vector");
}
}
// 具体实现:栅格渲染
class RasterRenderer implements Renderer {
@Override
public void renderShape(String shape) {
System.out.println("Drawing " + shape + " as pixels");
}
}
// 抽象部分
abstract class Shape {
protected Renderer renderer;
public Shape(Renderer renderer) {
this.renderer = renderer;
}
public abstract void draw();
}
// 扩展抽象:圆形
class Circle extends Shape {
public Circle(Renderer renderer) {
super(renderer);
}
@Override
public void draw() {
renderer.renderShape("Circle");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Renderer vector = new VectorRenderer();
Shape circle = new Circle(vector);
circle.draw(); // 输出: Drawing Circle as vector
}
}
适用场景
- 多维度变化的系统(如形状 + 渲染方式)
- 避免类爆炸(如 MxN 种组合)
优缺点
- 优点:解耦抽象与实现,扩展性强。
- 缺点:增加系统设计复杂度。
3. 组合模式(Composite)
定义
将对象组织成树形结构,统一处理单个对象和组合对象。
类图
┌───────────────────┐
│ Component │
├───────────────────┤
│ +add() │
│ +remove() │
│ +getChild() │
│ +operation() │
└──────┬────────────┘
△
│
├──────────────────┐
│ │
┌───────────────┐ ┌───────────────┐
│ Leaf │ │ Composite │
├───────────────┤ ├───────────────┤
│ +operation() │ │ -children │
└───────────────┘ │ +add() │
│ +remove() │
│ +operation() │
└───────────────┘
Java 实现
// 抽象组件
interface FileSystemComponent {
void display();
}
// 叶子节点:文件
class File implements FileSystemComponent {
private String name;
public File(String name) { this.name = name; }
@Override
public void display() {
System.out.println("File: " + name);
}
}
// 组合节点:目录
class Directory implements FileSystemComponent {
private String name;
private List<FileSystemComponent> children = new ArrayList<>();
public Directory(String name) { this.name = name; }
public void add(FileSystemComponent component) {
children.add(component);
}
@Override
public void display() {
System.out.println("Directory: " + name);
for (FileSystemComponent child : children) {
child.display();
}
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Directory root = new Directory("root");
root.add(new File("file1.txt"));
Directory subDir = new Directory("sub");
subDir.add(new File("file2.txt"));
root.add(subDir);
root.display(); // 输出目录树结构
}
}
适用场景
- 文件系统、UI 组件树
- 需要统一处理部分与整体的场景
优缺点
- 优点:简化客户端代码,支持递归组合。
- 缺点:设计过于通用,可能违反接口隔离原则。
4. 装饰器模式(Decorator)
定义
动态地为对象添加额外职责,替代继承的扩展方式。
类图
┌───────────────────┐ ┌───────────────────┐
│ Component │<>─────│ Decorator │
├───────────────────┤ ├───────────────────┤
│ +operation() │ │ -component │
└───────────────────┘ │ +operation() │
△ └─────────┬─────────┘
│ △
│ │
├───────────────────────────────┘
│
┌───────────────┐ ┌───────────────────┐
│ ConcreteComp │ │ ConcreteDecorator │
├───────────────┤ ├───────────────────┤
│ +operation() │ │ +operation() │
└───────────────┘ │ +addedBehavior() │
└───────────────────┘
Java 实现
// 基础组件接口
interface Coffee {
double getCost();
String getDescription();
}
// 具体组件
class SimpleCoffee implements Coffee {
@Override
public double getCost() { return 2.0; }
@Override
public String getDescription() { return "Simple Coffee"; }
}
// 抽象装饰器
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
public double getCost() {
return decoratedCoffee.getCost();
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
}
// 具体装饰器:加牛奶
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) { super(coffee); }
@Override
public double getCost() {
return super.getCost() + 0.5;
}
@Override
public String getDescription() {
return super.getDescription() + ", Milk";
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " - $" + coffee.getCost());
// 输出: Simple Coffee, Milk - $2.5
}
}
适用场景
- Java I/O 流(如
BufferedInputStream包装FileInputStream) - 动态扩展对象功能
优缺点
- 优点:避免类爆炸,运行时扩展。
- 缺点:多层装饰增加复杂性。
5. 外观模式(Facade)
定义
为复杂子系统提供一个统一的简化接口。
类图
┌───────────────────┐ ┌───────────────────┐
│ Facade │──────▶│ Subsystem Classes │
├───────────────────┤ ├───────────────────┤
│ +simpleMethod() │ │ +operationA() │
└───────────────────┘ │ +operationB() │
└───────────────────┘
Java 实现
// 子系统类
class CPU {
void start() { System.out.println("CPU启动"); }
}
class Memory {
void load() { System.out.println("内存加载"); }
}
class HardDrive {
void read() { System.out.println("硬盘读取"); }
}
// 外观类
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
public void startComputer() {
cpu.start();
memory.load();
hardDrive.read();
System.out.println("计算机启动完成");
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.startComputer(); // 隐藏子系统复杂调用
}
}
适用场景
- 简化复杂库或框架的使用
- 分层结构中的中间层设计
优缺点
- 优点:降低客户端复杂度,解耦子系统。
- 缺点:可能成为“上帝对象”,违反单一职责原则。
6. 享元模式(Flyweight)
定义
通过共享技术高效支持大量细粒度对象。
类图
┌───────────────────┐ ┌───────────────────┐
│ FlyweightFactory │ │ Flyweight │
├───────────────────┤ ├───────────────────┤
│ -cache: Map │ │ +operation() │
│ +getFlyweight() │ └─────────┬─────────┘
└───────────────────┘ △
│
┌───────────────┐
│ ConcreteFlyweight
├───────────────┤
│ +operation() │
└───────────────┘
Java 实现
// 享元接口
interface TreeType {
void draw(int x, int y);
}
// 具体享元:树的类型(内部状态)
class ConcreteTreeType implements TreeType {
private String name;
private String color;
public ConcreteTreeType(String name, String color) {
this.name = name;
this.color = color;
}
@Override
public void draw(int x, int y) {
System.out.printf("在(%d,%d)绘制%s色的%s树\n", x, y, color, name);
}
}
// 享元工厂
class TreeFactory {
private static Map<String, TreeType> cache = new HashMap<>();
public static TreeType getTreeType(String name, String color) {
String key = name + "_" + color;
if (!cache.containsKey(key)) {
cache.put(key, new ConcreteTreeType(name, color));
}
return cache.get(key);
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
TreeType oakGreen = TreeFactory.getTreeType("Oak", "Green");
oakGreen.draw(10, 20); // 复用已有对象
}
}
适用场景
- 文本编辑器中的字符对象池
- 游戏中的大量粒子效果
优缺点
- 优点:大幅减少内存占用。
- 缺点:增加对象状态管理复杂度(需区分内部/外部状态)。
7. 代理模式(Proxy)
定义
为其他对象提供代理以控制对该对象的访问。
类图
┌───────────────────┐ ┌───────────────────┐
│ Subject │ │ Proxy │
├───────────────────┤ ├───────────────────┤
│ +request() │ │ -realSubject │
└──────┬────────────┘ │ +request() │
△ └─────────┬─────────┘
│ │
│ ┌───────▼───────┐
│ │ RealSubject │
│ ├───────────────┤
└───────────────────────┤ +request() │
└───────────────┘
Java 实现
// 抽象主题
interface Image {
void display();
}
// 真实主题
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片: " + filename);
}
@Override
public void display() {
System.out.println("显示图片: " + filename);
}
}
// 代理类
class ImageProxy implements Image {
private RealImage realImage;
private String filename;
public ImageProxy(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename); // 延迟加载
}
realImage.display();
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Image image = new ImageProxy("test.jpg");
image.display(); // 第一次触发真实对象加载
}
}
适用场景
- 虚拟代理(延迟加载大对象)
- 保护代理(权限控制)
优缺点
- 优点:控制对象访问,增强安全性。
- 缺点:可能引入性能开销。
总结
| 模式 | 核心目标 | 典型场景 |
|---|---|---|
| 适配器 | 接口转换 | 旧系统兼容 |
| 桥接 | 分离抽象与实现 | 多维度变化的系统 |
| 组合 | 统一处理部分与整体 | 树形结构管理 |
| 装饰器 | 动态添加职责 | I/O流扩展 |
| 外观 | 简化复杂子系统 | 一键操作封装 |
| 享元 | 共享细粒度对象 | 游戏粒子系统 |
| 代理 | 控制对象访问 | 延迟加载、权限控制 |
最佳实践:
- 优先使用组合而非继承(如装饰器模式)。
- 享元模式需明确区分内部/外部状态。
- 代理模式可结合动态代理(如 Java 的
Proxy类)实现更灵活的拦截。