con un clic
bridge
将抽象与实现分离,使二者可独立变化
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
将抽象与实现分离,使二者可独立变化
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。
在DDD中具有唯一身份标识和生命周期的对象,通过身份而非属性值相等判断。
封装复杂对象和聚合的创建过程,将创建职责从领域对象中剥离,保证聚合创建时的不变量满足。
没有身份标识,通过属性值判断相等的对象。不可变,通常代表领域中的度量或描述。
命令查询责任分离,将数据的写入操作和读取操作分别用不同的模型处理,优化各自的性能。
将DDD战略设计应用于微服务架构,限界上下文指导服务拆分,领域事件实现服务间通信。
| name | Bridge |
| description | 将抽象与实现分离,使二者可独立变化 |
| license | MIT |
Bridge 是一种结构型设计模式,用于将抽象与实现分离,使它们可以独立变化。
| 继承 | 桥接 |
|---|---|
| Shape → Circle, Square | Shape + Renderer的组合 |
| 类爆炸(M×N个类) | 只需M+N个类 |
| 静态结构 | 动态灵活 |
| 修改一维影响全部 | 维度独立变化 |
Abstraction Implementor
△ △
│ │
┌─────────┼─────────┐ ┌────────┴────────┐
│ │ │ │ │
RefinedAbstraction ConcreteImplementorA ConcreteImplementorB
// 实现接口
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();
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);
}
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();
// 抽象
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(); // 跨平台
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";
}
}
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(...);
}
}
// 抽象维度:支付方式
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);
}
}
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);
}
}
// 传输协议(实现维度)
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());
}
}
// 实现维度:渲染引擎
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());
}
}
// 存储介质(实现维度)
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个类
独立变化 - 一个维度变化不影响另一个
✓ Shape和Color独立 → 分离
✗ Button和ButtonListener不独立 → 不分离
正交性 - 两个维度没有强依赖
✓ Window和OS是正交的
✗ ListNode和DoubleLinkedListNode不正交
各自可配置 - 都需要运行时决策
✓ Shape(Circle/Square) + Color(Red/Green) 都需要选择
✗ Object和Class不需要同时选择 → 不用桥接
是否有M×N的类爆炸?
├─ 是 → 考虑桥接
└─ 否 → 继承足够
两个维度独立变化?
├─ 是 → 进一步优化用桥接
└─ 否 → 继承更好
都需要运行时选择?
├─ 是 → 使用桥接✅
└─ 否 → 考虑其他
症状: 分不清什么是真独立,什么是虚独立
分析工具 - 变化频率矩阵:
维度组合 Shape变化频率 Renderer变化频率
─────────────────────────────────────────────────
Circle+GPU 每月1次 每周1次 ✅ 独立
Window+OS 每周1次 每月1次 ✅ 独立
Employee+Role 几乎不变 每年1次 ⚠️ 伪独立
Button+Color 经常 很少 ⚠️ 非对称
判断:如果两个维度的变化频率差异>5倍,或一个几乎不变 → 虚独立 → 不用桥接
错误示例(伪独立):
// ❌ 不应该用桥接
public abstract class PaymentMethod {
protected PaymentProcessor processor; // 伪桥接
}
// 原因:PaymentMethod和Processor不独立
// Processor是PaymentMethod的依赖,不是平行维度
正确示例(真独立):
// ✅ 真正的桥接
public abstract class Logger {
protected LogOutput output; // 真桥接
}
// 原因:Logger(级别)和Output(目标)互不依赖,独立变化
规则:
Abstraction:
→ 高层业务逻辑
→ 稳定的部分
→ 不经常变化
Implementor:
→ 低层技术细节
→ 易变的部分
→ 经常替换
判断标准 - 稳定性分析:
// 分析:哪个更稳定?
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实现细节,不是业务抽象
}
场景: 运行时需要改变Implementor(如切换数据库)
方案1: Setter切换(推荐简单场景)
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: 工厂切换(推荐复杂场景)
public class DialectFactory {
private static Map<String, DatabaseDialect> dialects = new HashMap<>();
static {
dialects.put("mysql", new MySQLDialect());
dialects.put("postgres", new PostgreSQLDialect());
dialects.put("oracle", new OracleDialect());
}
public static DatabaseDialect getDialect(String dbType) {
return dialects.get(dbType);
}
}
// 使用:从配置读取
DatabaseDialect dialect = DialectFactory.getDialect(config.getDbType());
DataService service = new DataService(dialect);
方案3: 策略切换(推荐高频切换)
public class AdaptiveService {
private Map<String, DatabaseDialect> dialects;
private DatabaseDialect current;
public void executeWithBestDialect(Query q) {
// 分析Query特征,选择最优Implementor
DatabaseDialect best = selectBest(q);
// 切换
this.current = best;
current.execute(q);
}
private DatabaseDialect selectBest(Query q) {
if (q.isSimple()) return dialects.get("sqlite");
if (q.isComplex()) return dialects.get("postgres");
return dialects.get("mysql");
}
}
症状: Abstraction引用Implementor,Implementor又需要Abstraction
反面示例(循环):
// ❌ 循环依赖
public abstract class Shape {
protected Renderer renderer;
public void render() {
renderer.render(this); // Shape传给Renderer
}
}
public interface Renderer {
void render(Shape shape); // Renderer依赖Shape
}
// 问题:Shape和Renderer相互依赖
正确示例(单向依赖):
// ✅ 单向依赖:Shape→Renderer
public abstract class Shape {
protected Renderer renderer;
public void render() {
Color c = getColor();
Size s = getSize();
renderer.render(c, s); // 只传递必要数据,不传Shape
}
}
public interface Renderer {
void render(Color color, Size size); // 无需知道Shape
}
// 场景:同时有Shape、Color、Renderer三个维度
public abstract class Shape {
protected ColorRenderer colorRenderer;
protected GeometryRenderer geometryRenderer;
public void render() {
geometryRenderer.render(this);
colorRenderer.render(this);
}
}
// 或者用组合模式
public class MultiDimensionalBridge {
private Map<String, Renderer> renderers = new HashMap<>();
public void register(String dimension, Renderer renderer) {
renderers.put(dimension, renderer);
}
public void render(Shape shape) {
renderers.values().forEach(r -> r.render(shape));
}
}
public class DynamicBridge {
private Object implementor;
private Class<?> implementorInterface;
public DynamicBridge(Object impl, Class<?> iface) {
this.implementor = impl;
this.implementorInterface = iface;
}
public Object invoke(String methodName, Object... args) {
return MethodHandle.from(implementor, methodName)
.invokeWithArguments(args);
}
}
// 使用
DynamicBridge bridge = new DynamicBridge(
new MySQLDialect(),
DatabaseDialect.class
);
bridge.invoke("query", sqlStatement); // 动态调用
| 模式 | 区别 | 何时结合 |
|---|---|---|
| Adapter | Adapter修补不兼容;Bridge分离设计 | 先用Bridge设计,Adapter处理遗留系统 |
| Strategy | Strategy处理算法选择;Bridge分离维度 | Bridge用于类层次,Strategy用于运行时选择 |
| Composite | Composite处理树结构;Bridge分离维度 | 多维树可同时用:Bridge分离Color,Composite管理父子 |
| Factory | Factory创建对象;Bridge分离实现 | 结合使用:BridgeFactory创建合适的Abstraction-Implementor对 |
| Decorator | Decorator逐层增强;Bridge分离实现 | 可结合:Decorator在Abstraction层做装饰 |