Skip to main content

bridge

将抽象与实现分离,使二者可独立变化

Informações da origem

Repositório
microwind/ai-skills
Última atividade na origem
31 de março de 2026 às 01:27
Idioma detectado do SKILL.md
chinês
Estrelas
88
Forks
24

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
4 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
Bridge
description
将抽象与实现分离,使二者可独立变化
license
MIT
# Bridge Pattern (桥接模式) ## 核心概念 **Bridge** 是一种**结构型设计模式**,用于将抽象与实现分离,使它们可以独立变化。 ### 关键原理 - 🔗 **分离关切** (Separation of Concerns) - 抽象与实现分开 - 📐 **维度分离** - 按不同维度定义类层级 - 🔄 **独立变化** - 抽象和实现都能独立扩展 - ✏️ **灵活组合** - 通过组合实现多维特性 ### 对比继承 | 继承 | 桥接 | |------|------| | Shape → Circle, Square | Shape + Renderer的组合 | | 类爆炸(M×N个类) | 只需M+N个类 | | 静态结构 | 动态灵活 | | 修改一维影响全部 | 维度独立变化 | ## 何时使用 1. **两个独立维度的变化** - Color × Shape、OS × Window、Device × Renderer 2. **避免类爆炸** - 用组合代替多重继承 3. **隐藏实现细节** - 客户端只见抽象 4. **运行时切换实现** - 动态决定使用哪个Implementor 5. **共享实现** - 多个Abstraction复用同一Implementor ## 基本结构 ### UML类图 ``` Abstraction Implementor △ △ │ │ ┌─────────┼─────────┐ ┌────────┴────────┐ │ │ │ │ │ RefinedAbstraction ConcreteImplementorA ConcreteImplementorB ``` ## 实现方式 ### 方法1: 虚方法模式 ```java // 实现接口 public interface Renderer { void renderCircle(); } // 实现者 public class PyramidRenderer implements Renderer { @Override public void renderCircle() { System.out.println(" ^ "); System.out.println(" / \ "); } } // 抽象(包含对Implementor的引用) public abstract class Shape { protected Renderer renderer; public Shape(Renderer renderer) { this.renderer = renderer; } public abstract void draw(); } // 精化抽象 public class Circle extends Shape { @Override public void draw() { renderer.renderCircle(); } } // 使用 Renderer r = new PyramidRenderer(); Shape s = new Circle(r); s.draw(); ``` ### 方法2: 参数化桥接 ```java public abstract class AbstractShape { private Map<String, Renderer> renderers; public AbstractShape() { this.renderers = new HashMap<>(); initializeRenderers(); } protected abstract void initializeRenderers(); public void drawWith(String renderType) { Renderer renderer = renderers.get(renderType); if (renderer != null) { performDraw(renderer); } } protected abstract void performDraw(Renderer r); } ``` ### 方法3: 配置驱动 ```java public class BridgeFactory { public static Shape create(String shapeType, String renderType) { Renderer renderer = createRenderer(renderType); return createShape(shapeType, renderer); } private static Renderer createRenderer(String type) { // 从配置或工厂创建Renderer return RendererFactory.create(type); } private static Shape createShape(String type, Renderer r) { switch (type) { case "circle": return new Circle(r); case "square": return new Square(r); default: throw new IllegalArgumentException(type); } } } // 使用 Shape shape = BridgeFactory.create("circle", "pyramid"); shape.draw(); ``` ## 完美使用场景 ### 场景1: 跨平台UI - Window与OS适配 ```java // 抽象 public abstract class Window { protected OS os; public Window(OS os) { this.os = os; } } // 具体窗口 public class StandardWindow extends Window { public void render() { os.drawWindow("Standard"); } } // 实现者 public interface OS { void drawWindow(String style); } // 具体平台 public class WindowsOS implements OS { public void drawWindow(String style) { System.out.println("Rendering on Windows: " + style); } } // 使用 OS os = getOS(); // 运行时决定 Window win = new StandardWindow(os); win.render(); // 跨平台 ``` ### 场景2: 数据库访问 - 数据库方言 ```java public abstract class DataMapper { protected DatabaseDialect dialect; } public class UserMapper extends DataMapper { public List<User> findAll() { String sql = dialect.createSelectSQL("users"); return dialect.execute(sql); } } // MySQL方言 public class MySQLDialect implements DatabaseDialect { @Override public String createSelectSQL(String table) { return "SELECT * FROM " + table + " LIMIT 100"; } } // PostgreSQL方言 public class PostgreSQLDialect implements DatabaseDialect { @Override public String createSelectSQL(String table) { return "SELECT * FROM " + table + " OFFSET 0 LIMIT 100"; } } ``` ### 场景3: 设备驱动 - 图形渲染 ```java public interface Renderer { void renderPixel(int x, int y, Color color); void drawLine(int x1, int y1, int x2, int y2); } public class GPURenderer implements Renderer { public void renderPixel(int x, int y, Color color) { // 调用GPU API cuda.setPixel(x, y, color); } } public abstract class Graphic { protected Renderer renderer; public abstract void draw(); } public class Circle extends Graphic { private int radius; public void draw() { // 使用renderer接口,独立于GPU/CPU renderer.drawLine(...); } } ``` ### 场景4: 支付系统 - 支付方式与支付渠道 ```java // 抽象维度:支付方式 public interface PaymentMethod { double calculateFee(double amount); boolean validate(String info); } // 实现维度:支付渠道 public interface PaymentChannel { Receipt charge(double amount); Receipt refund(String receiptId); } // 具体支付方式 public class CreditCard implements PaymentMethod { public double calculateFee(double amount) { return amount * 0.02; // 2%手续费 } } // 具体支付渠道 public class AlipayChannel implements PaymentChannel { public Receipt charge(double amount) { // 调用Alipay API return alipayAPI.pay(amount); } } // 桥接:支付处理 public abstract class PaymentProcessor { protected PaymentMethod method; protected PaymentChannel channel; public Receipt processPayment(double amount) { double fee = method.calculateFee(amount); double total = amount + fee; return channel.charge(total); } } ``` ### 场景5: 日志系统 - 日志级别与输出目标 ```java public interface LogOutput { void write(String message); void flush(); } public class FileLogOutput implements LogOutput { public void write(String message) { fileWriter.println(message); } } public abstract class Logger { protected LogOutput output; protected LogLevel level; protected void log(String message) { if (shouldLog()) { output.write(formatMessage(message)); } } protected abstract String formatMessage(String message); } public class StructuredLogger extends Logger { protected String formatMessage(String message) { return String.format("[%s] %s", level, message); } } ``` ### 场景6: 消息队列 - 消息格式与传输协议 ```java // 传输协议(实现维度) public interface Transport { void send(Message msg); Message receive(); void connect(String brokerUrl); } // 消息格式(抽象维度) public abstract class Message { protected Transport transport; abstract byte[] serialize(); } // JSON消息 public class JSONMessage extends Message { byte[] serialize() { return gson.toJson(this).getBytes(); } } // TCP传输 public class TCPTransport implements Transport { public void send(Message msg) { byte[] data = msg.serialize(); socket.send(data); } } // AMQP传输 public class AMQPTransport implements Transport { public void send(Message msg) { channel.basicPublish(msg.serialize()); } } ``` ### 场景7: 主题(Pattern,配置系统 - UI主题与渲染引擎 ```java // 实现维度:渲染引擎 public interface RenderEngine { void drawButton(Theme theme, String label); void drawWindow(Theme theme, String title); } // 抽象维度:UI主题 public abstract class UITheme { protected RenderEngine engine; abstract void applyColors(); public void renderUI() { applyColors(); engine.drawWindow(this, "Main"); engine.drawButton(this, "OK"); } } // 浅色主题 public class LightTheme extends UITheme { void applyColors() { backgroundColor = Color.WHITE; textColor = Color.BLACK; } } // SWT渲染 public class SWTEngine implements RenderEngine { public void drawButton(UITheme theme, String label) { button = new Button(shell, SWT.PUSH); button.setText(label); button.setBackground(theme.getBackgroundColor()); } } // Swing渲染 public class SwingEngine implements RenderEngine { public void drawButton(UITheme theme, String label) { JButton btn = new JButton(label); btn.setBackground(theme.getBackgroundColor()); } } ``` ### 场景8: 数据存储 - 数据格式与存储介质 ```java // 存储介质(实现维度) public interface Storage { void save(byte[] data); byte[] load(); } // 数据格式(抽象维度) public abstract class DataStore { protected Storage storage; abstract byte[] encode(); abstract Object decode(byte[] data); public void persist(Object obj) { byte[] encoded = encode(obj); storage.save(encoded); } } // CSV格式 public class CSVDataStore extends DataStore { byte[] encode(Object obj) { return CSV.serialize(obj); } } // 文件存储 public class FileStorage implements Storage { public void save(byte[] data) { FileOutputStream.write(data); } } // 云存储(AWS S3) public class S3Storage implements Storage { public void save(byte[] data) { s3Client.putObject(bucketName, key, data); } } ``` --- ## "分离"与"独立变化"的核心理解 ### 为什么要分离?(核心原理) 桥接模式的本质是**解决两个独立变化维度的类爆炸问题**。 ``` ❌ 不用桥接:继承树爆炸 Shape ├── Circle │ ├── CircleRed (Shape×Color的笛卡尔积) │ ├── CircleGreen │ └── CircleBlue ├── Square │ ├── SquareRed │ ├── SquareGreen │ └── SquareBlue └── Triangle ├── TriangleRed ├── TriangleGreen └── TriangleBlue # 总计: 3 Shape × 3 Color = 9个类 ✅ 用桥接:矩阵分离 Shape: Circle, Square, Triangle (3个) Color: Red, Green, Blue (3个) # 总计: 3 + 3 = 6个类 # 组合: 3 × 3 = 9种对象,但只需6个类 ``` ### 分离的两个维度必须满足什么条件? 1. **独立变化** - 一个维度变化不影响另一个 ``` ✓ Shape和Color独立 → 分离 ✗ Button和ButtonListener不独立 → 不分离 ``` 2. **正交性** - 两个维度没有强依赖 ``` ✓ Window和OS是正交的 ✗ ListNode和DoubleLinkedListNode不正交 ``` 3. **各自可配置** - 都需要运行时决策 ``` ✓ Shape(Circle/Square) + Color(Red/Green) 都需要选择 ✗ Object和Class不需要同时选择 → 不用桥接 ``` ### 判断是否应该用桥接 ``` 是否有M×N的类爆炸? ├─ 是 → 考虑桥接 └─ 否 → 继承足够 两个维度独立变化? ├─ 是 → 进一步优化用桥接 └─ 否 → 继承更好 都需要运行时选择? ├─ 是 → 使用桥接✅ └─ 否 → 考虑其他 ``` --- ## 深入的常见问题解决 ### 问题1: 什么时候是"真正"的两个独立维度? **症状**: 分不清什么是真独立,什么是虚独立 **分析工具 - 变化频率矩阵**: ``` 维度组合 Shape变化频率 Renderer变化频率 ───────────────────────────────────────────────── Circle+GPU 每月1次 每周1次 ✅ 独立 Window+OS 每周1次 每月1次 ✅ 独立 Employee+Role 几乎不变 每年1次 ⚠️ 伪独立 Button+Color 经常 很少 ⚠️ 非对称 判断:如果两个维度的变化频率差异>5倍,或一个几乎不变 → 虚独立 → 不用桥接 ``` **错误示例**(伪独立): ```java // ❌ 不应该用桥接 public abstract class PaymentMethod { protected PaymentProcessor processor; // 伪桥接 } // 原因:PaymentMethod和Processor不独立 // Processor是PaymentMethod的依赖,不是平行维度 ``` **正确示例**(真独立): ```java // ✅ 真正的桥接 public abstract class Logger { protected LogOutput output; // 真桥接 } // 原因:Logger(级别)和Output(目标)互不依赖,独立变化 ``` ### 问题2: 抽象与实现应该如何划分? **规则**: ``` Abstraction: → 高层业务逻辑 → 稳定的部分 → 不经常变化 Implementor: → 低层技术细节 → 易变的部分 → 经常替换 ``` **判断标准 - 稳定性分析**: ```java // 分析:哪个更稳定? Logger logger = new Logger("FILE", LogLevel.DEBUG); // 稳定 // vs FileWriter fw = new FileWriter("/path/to/file.log"); // 易变 // Logger(抽象): 业务需要的日志级别 → 稳定 // FileWriter(实现): 具体输出目标 → 易变 // → Logger是Abstraction, FileWriter是Implementor ✅ // 反例:混淆了 public class Logger { protected Renderer renderer; // 反了! // Logger实现细节,不是业务抽象 } ``` ### 问题3: 如何动态切换Bridge的两端? **场景**: 运行时需要改变Implementor(如切换数据库) **方案1: Setter切换**(推荐简单场景) ```java public class DataService { private DatabaseDialect dialect; public void setDialect(DatabaseDialect d) { this.dialect = d; } public List<User> getUsers() { return dialect.query("SELECT * FROM users"); } } // 使用 DataService service = new DataService(); service.setDialect(new MySQLDialect()); service.getUsers(); // 切换 service.setDialect(new PostgreSQLDialect()); service.getUsers(); // 同一个service,不同backend ``` **方案2: 工厂切换**(推荐复杂场景) ```java public class DialectFactory { private static Map<String, DatabaseDialect> dialects = new HashMap<>(); static { dialects.put("mysql", new MySQLDialect()); dialects.put("postgres", new PostgreSQLDialect());
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub