系列导读:在学习了接口适配后,我们来看如何处理抽象与实现的分离问题。桥接模式解决的是"多维度变化"的设计难题。
解决什么问题:将抽象部分与实现部分分离,使它们都可以独立变化。避免在多个维度上变化时出现类爆炸问题。
想象一下,你要设计一个图形绘制系统,既要支持不同的形状(圆形、矩形),又要支持不同的绘制方式(Windows绘制、Linux绘制)。如果用继承,你需要WindowsCircle、LinuxCircle、WindowsRectangle、LinuxRectangle等类,随着形状和平台的增加,类的数量会爆炸式增长。
桥接模式通过将"形状"和"绘制方式"分离成两个独立的层次结构,用组合代替继承,让两个维度可以独立变化和扩展。
本文在系列中的位置:
目录
1. 模式概述
桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。这种模式通过组合的方式,而不是继承的方式,来实现抽象和实现的解耦。桥接模式常用于需要多维度扩展的系统,能够有效避免类爆炸问题。
定义
桥接模式将抽象部分与实现部分分离,使它们都可以独立地变化。通过在抽象层中持有实现层的引用,实现抽象和实现的解耦,便于系统的扩展和维护。
目的
- 分离抽象与实现,避免继承导致的类爆炸
- 支持抽象和实现的独立扩展,提升系统灵活性
- 降低系统耦合度,便于维护和升级
2. 使用场景
桥接模式适用于以下场景:
抽象和实现分离
- 需要将抽象和实现分离,便于独立扩展。
- 需要支持多种实现方式,避免继承的局限性。
- 需要在运行时切换实现。
多维度变化
- 系统存在多个变化维度,如形状和颜色、平台和功能等。
- 需要避免因多维扩展导致的类爆炸。
- 需要灵活组合不同维度的实现。
运行时绑定
- 需要在运行时动态切换实现。
- 需要支持插件化、可插拔架构。
- 需要动态改变实现方式。
真实业务背景举例:
- 跨平台UI库,既要支持多种控件类型(如按钮、文本框),又要支持多种操作系统(如Windows、Linux、Mac),通过桥接模式实现控件与平台的解耦。
- 图形绘制系统,既要支持多种图形(如圆形、矩形),又要支持多种绘图API(如OpenGL、DirectX),通过桥接模式灵活组合。
- 云存储平台支持多种存储后端(如本地磁盘、阿里云OSS、亚马逊S3),通过桥接模式灵活切换存储实现。
3. 优缺点分析
优点
- 解耦:抽象和实现分离,降低代码耦合度。提高代码可维护性和扩展性。支持独立演化和升级。
- 扩展性:支持多维度独立扩展,符合开闭原则。避免继承导致的类爆炸。易于添加新的抽象或实现。
- 灵活性:支持运行时切换实现,提升系统灵活性。支持动态组合不同实现。便于实现插件化架构。
缺点
- 复杂性提升:增加系统结构复杂度。需要合理设计抽象和实现层次。增加理解和维护难度。
- 设计难度:需要合理划分抽象和实现。需要处理两者之间的关系。需要保持接口一致性。
- 维护成本:需要维护多个类和接口。需要处理版本兼容和扩展问题。需要保证系统整体一致性。
4. 实际应用案例
- GUI框架:跨平台控件(如按钮、文本框在不同操作系统下的实现)、主题切换(如不同UI主题的动态切换)、控件风格扩展(如扁平风格、拟物风格等)。
- 数据库访问:支持多种数据库类型(MySQL、Oracle、SQL Server等)、多种连接方式(JDBC、ODBC等)、多种查询方式(SQL、NoSQL等)。
- 消息系统:支持多种消息类型(文本、图片、视频等)、多种发送方式(HTTP、MQ、WebSocket等)、多种处理方式(同步、异步等)。
- 文件系统:支持多种存储方式(本地、云端、分布式等)、多种文件格式(txt、pdf、doc等)、多种访问方式(读、写、删除等)。
5. 结构与UML类图
@startuml
package "Bridge Pattern" #DDDDDD {
interface DrawingAPI {
+ drawCircle(x: int, y: int, radius: int): void
+ drawRectangle(x: int, y: int, width: int, height: int): void
}
class WindowsDrawingAPI implements DrawingAPI
class LinuxDrawingAPI implements DrawingAPI
abstract class Shape {
# drawingAPI: DrawingAPI
+ draw(): void
}
class Circle extends Shape
class Rectangle extends Shape
DrawingAPI <|.. WindowsDrawingAPI
DrawingAPI <|.. LinuxDrawingAPI
Shape <|-- Circle
Shape <|-- Rectangle
Shape o-- DrawingAPI : drawingAPI
}
@enduml
6. 代码示例
6.1 基本结构示例
业务背景: 实现抽象与实现分离的基本结构,支持运行时切换实现。
package com.example.patterns.bridge;
import java.util.Objects;
// 实现接口,定义实现层的操作
public interface Implementor {
/**
* 实现层的具体操作
* 业务含义:底层平台或品牌的具体实现
*/
void operationImpl();
/**
* 获取实现类型
*/
String getType();
}
// 具体实现A,实现Implementor接口
public class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
try {
// 具体实现A的业务逻辑
System.out.println("ConcreteImplementorA operation - 执行实现A的业务逻辑");
} catch (Exception e) {
System.err.println("ImplementorA operation failed: " + e.getMessage());
throw new RuntimeException("实现A操作失败", e);
}
}
@Override
public String getType() {
return "ImplementorA";
}
}
// 具体实现B,实现Implementor接口
public class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
try {
// 具体实现B的业务逻辑
System.out.println("ConcreteImplementorB operation - 执行实现B的业务逻辑");
} catch (Exception e) {
System.err.println("ImplementorB operation failed: " + e.getMessage());
throw new RuntimeException("实现B操作失败", e);
}
}
@Override
public String getType() {
return "ImplementorB";
}
}
// 抽象类,持有实现接口的引用
public abstract class Abstraction {
protected final Implementor implementor;
/**
* 构造方法注入实现层,便于运行时切换
*/
public Abstraction(Implementor implementor) {
this.implementor = Objects.requireNonNull(implementor, "Implementor cannot be null");
}
/**
* 抽象层的操作,由子类实现
* 业务含义:对外暴露的统一接口
*/
public abstract void operation();
/**
* 获取当前实现类型
*/
public String getImplementorType() {
return implementor.getType();
}
}
// 扩展抽象类,实现具体的业务操作
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
try {
// 调用实现层的操作,实现桥接
System.out.println("RefinedAbstraction: 准备调用实现层");
implementor.operationImpl();
System.out.println("RefinedAbstraction: 完成调用实现层");
} catch (Exception e) {
System.err.println("Abstraction operation failed: " + e.getMessage());
throw new RuntimeException("抽象层操作失败", e);
}
}
}
6.2 企业级应用场景:消息推送系统
业务背景: 企业级消息推送系统需要支持多种消息类型(短信、邮件、推送通知)和多种推送平台(阿里云、腾讯云、华为云),通过桥接模式实现消息类型与推送平台的解耦。
package com.example.patterns.bridge.message;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.time.LocalDateTime;
// 推送平台接口
public interface MessagePlatform {
/**
* 发送消息
* @param recipient 接收者
* @param content 消息内容
* @param metadata 元数据
* @return 推送结果
*/
PushResult sendMessage(String recipient, String content, Map<String, Object> metadata);
/**
* 获取平台名称
*/
String getPlatformName();
/**
* 检查平台状态
*/
boolean isAvailable();
}
// 推送结果封装
public class PushResult {
private boolean success;
private String messageId;
private String platformName;
private String errorMessage;
private LocalDateTime timestamp;
public PushResult(boolean success, String messageId, String platformName, String errorMessage) {
this.success = success;
this.messageId = messageId;
this.platformName = platformName;
this.errorMessage = errorMessage;
this.timestamp = LocalDateTime.now();
}
// Getter方法
public boolean isSuccess() { return success; }
public String getMessageId() { return messageId; }
public String getPlatformName() { return platformName; }
public String getErrorMessage() { return errorMessage; }
public LocalDateTime getTimestamp() { return timestamp; }
@Override
public String toString() {
return String.format("PushResult{success=%s, messageId='%s', platform='%s', error='%s', time=%s}",
success, messageId, platformName, errorMessage, timestamp);
}
}
// 阿里云推送平台实现
public class AliyunMessagePlatform implements MessagePlatform {
private boolean available = true;
@Override
public PushResult sendMessage(String recipient, String content, Map<String, Object> metadata) {
try {
if (!isAvailable()) {
return new PushResult(false, null, getPlatformName(), "阿里云平台暂不可用");
}
// 模拟阿里云推送逻辑
String messageId = "aliyun_" + System.currentTimeMillis();
System.out.println("阿里云推送: 发送到 " + recipient + ", 内容: " + content);
return new PushResult(true, messageId, getPlatformName(), null);
} catch (Exception e) {
return new PushResult(false, null, getPlatformName(), "阿里云推送异常: " + e.getMessage());
}
}
@Override
public String getPlatformName() {
return "阿里云";
}
@Override
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
}
// 腾讯云推送平台实现
public class TencentMessagePlatform implements MessagePlatform {
private boolean available = true;
@Override
public PushResult sendMessage(String recipient, String content, Map<String, Object> metadata) {
try {
if (!isAvailable()) {
return new PushResult(false, null, getPlatformName(), "腾讯云平台暂不可用");
}
// 模拟腾讯云推送逻辑
String messageId = "tencent_" + System.currentTimeMillis();
System.out.println("腾讯云推送: 发送到 " + recipient + ", 内容: " + content);
return new PushResult(true, messageId, getPlatformName(), null);
} catch (Exception e) {
return new PushResult(false, null, getPlatformName(), "腾讯云推送异常: " + e.getMessage());
}
}
@Override
public String getPlatformName() {
return "腾讯云";
}
@Override
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
}
// 华为云推送平台实现
public class HuaweiMessagePlatform implements MessagePlatform {
private boolean available = true;
@Override
public PushResult sendMessage(String recipient, String content, Map<String, Object> metadata) {
try {
if (!isAvailable()) {
return new PushResult(false, null, getPlatformName(), "华为云平台暂不可用");
}
// 模拟华为云推送逻辑
String messageId = "huawei_" + System.currentTimeMillis();
System.out.println("华为云推送: 发送到 " + recipient + ", 内容: " + content);
return new PushResult(true, messageId, getPlatformName(), null);
} catch (Exception e) {
return new PushResult(false, null, getPlatformName(), "华为云推送异常: " + e.getMessage());
}
}
@Override
public String getPlatformName() {
return "华为云";
}
@Override
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
}
// 消息抽象类
public abstract class Message {
protected final MessagePlatform platform;
protected String title;
protected String content;
protected List<String> recipients;
protected Map<String, Object> metadata;
public Message(MessagePlatform platform) {
this.platform = Objects.requireNonNull(platform, "MessagePlatform cannot be null");
this.recipients = new ArrayList<>();
this.metadata = new HashMap<>();
}
public Message setTitle(String title) {
this.title = title;
return this;
}
public Message setContent(String content) {
this.content = content;
return this;
}
public Message addRecipient(String recipient) {
if (recipient != null && !recipient.trim().isEmpty()) {
this.recipients.add(recipient);
}
return this;
}
public Message addMetadata(String key, Object value) {
this.metadata.put(key, value);
return this;
}
/**
* 发送消息的抽象方法,由子类实现
*/
public abstract List<PushResult> send();
/**
* 格式化消息内容,由子类实现
*/
protected abstract String formatContent();
}
// 短信消息实现
public class SmsMessage extends Message {
public SmsMessage(MessagePlatform platform) {
super(platform);
}
@Override
public List<PushResult> send() {
List<PushResult> results = new ArrayList<>();
String formattedContent = formatContent();
for (String recipient : recipients) {
try {
PushResult result = platform.sendMessage(recipient, formattedContent, metadata);
results.add(result);
} catch (Exception e) {
PushResult errorResult = new PushResult(false, null, platform.getPlatformName(),
"发送短信异常: " + e.getMessage());
results.add(errorResult);
}
}
return results;
}
@Override
protected String formatContent() {
return "【短信通知】" + (title != null ? title + ": " : "") + content;
}
}
// 邮件消息实现
public class EmailMessage extends Message {
public EmailMessage(MessagePlatform platform) {
super(platform);
}
@Override
public List<PushResult> send() {
List<PushResult> results = new ArrayList<>();
String formattedContent = formatContent();
for (String recipient : recipients) {
try {
// 邮件特有的元数据
Map<String, Object> emailMetadata = new HashMap<>(metadata);
emailMetadata.put("subject", title);
emailMetadata.put("type", "email");
PushResult result = platform.sendMessage(recipient, formattedContent, emailMetadata);
results.add(result);
} catch (Exception e) {
PushResult errorResult = new PushResult(false, null, platform.getPlatformName(),
"发送邮件异常: " + e.getMessage());
results.add(errorResult);
}
}
return results;
}
@Override
protected String formatContent() {
StringBuilder html = new StringBuilder();
html.append("<html><body>");
if (title != null) {
html.append("<h2>").append(title).append("</h2>");
}
html.append("<p>").append(content).append("</p>");
html.append("</body></html>");
return html.toString();
}
}
// 推送通知消息实现
public class PushNotification extends Message {
public PushNotification(MessagePlatform platform) {
super(platform);
}
@Override
public List<PushResult> send() {
List<PushResult> results = new ArrayList<>();
String formattedContent = formatContent();
for (String recipient : recipients) {
try {
// 推送通知特有的元数据
Map<String, Object> pushMetadata = new HashMap<>(metadata);
pushMetadata.put("title", title);
pushMetadata.put("type", "push");
pushMetadata.put("badge", 1);
PushResult result = platform.sendMessage(recipient, formattedContent, pushMetadata);
results.add(result);
} catch (Exception e) {
PushResult errorResult = new PushResult(false, null, platform.getPlatformName(),
"发送推送通知异常: " + e.getMessage());
results.add(errorResult);
}
}
return results;
}
@Override
protected String formatContent() {
return content;
}
}
// 消息工厂
public class MessageFactory {
public static Message createSmsMessage(MessagePlatform platform) {
return new SmsMessage(platform);
}
public static Message createEmailMessage(MessagePlatform platform) {
return new EmailMessage(platform);
}
public static Message createPushNotification(MessagePlatform platform) {
return new PushNotification(platform);
}
}
// 平台工厂
public class PlatformFactory {
public static MessagePlatform createAliyunPlatform() {
return new AliyunMessagePlatform();
}
public static MessagePlatform createTencentPlatform() {
return new TencentMessagePlatform();
}
public static MessagePlatform createHuaweiPlatform() {
return new HuaweiMessagePlatform();
}
}
6.3 绘图系统场景
业务背景: 跨平台绘图系统,支持多种形状和多种绘图API的组合。
package com.example.patterns.bridge.graphics;
import java.awt.Color;
// 绘图API接口
public interface DrawingAPI {
void drawCircle(double x, double y, double radius, Color color);
void drawRectangle(double x, double y, double width, double height, Color color);
void drawLine(double x1, double y1, double x2, double y2, Color color);
String getApiName();
}
// Windows绘图API实现
public class WindowsDrawingAPI implements DrawingAPI {
@Override
public void drawCircle(double x, double y, double radius, Color color) {
System.out.printf("Windows API: 绘制圆形 at (%.1f,%.1f) radius=%.1f color=%s%n",
x, y, radius, color.toString());
}
@Override
public void drawRectangle(double x, double y, double width, double height, Color color) {
System.out.printf("Windows API: 绘制矩形 at (%.1f,%.1f) size=%.1fx%.1f color=%s%n",
x, y, width, height, color.toString());
}
@Override
public void drawLine(double x1, double y1, double x2, double y2, Color color) {
System.out.printf("Windows API: 绘制直线 from (%.1f,%.1f) to (%.1f,%.1f) color=%s%n",
x1, y1, x2, y2, color.toString());
}
@Override
public String getApiName() {
return "Windows GDI";
}
}
// Linux绘图API实现
public class LinuxDrawingAPI implements DrawingAPI {
@Override
public void drawCircle(double x, double y, double radius, Color color) {
System.out.printf("Linux X11: 绘制圆形 at (%.1f,%.1f) radius=%.1f color=%s%n",
x, y, radius, color.toString());
}
@Override
public void drawRectangle(double x, double y, double width, double height, Color color) {
System.out.printf("Linux X11: 绘制矩形 at (%.1f,%.1f) size=%.1fx%.1f color=%s%n",
x, y, width, height, color.toString());
}
@Override
public void drawLine(double x1, double y1, double x2, double y2, Color color) {
System.out.printf("Linux X11: 绘制直线 from (%.1f,%.1f) to (%.1f,%.1f) color=%s%n",
x1, y1, x2, y2, color.toString());
}
@Override
public String getApiName() {
return "Linux X11";
}
}
// 形状抽象类
public abstract class Shape {
protected final DrawingAPI drawingAPI;
protected double x, y;
protected Color color;
public Shape(DrawingAPI drawingAPI, double x, double y, Color color) {
this.drawingAPI = Objects.requireNonNull(drawingAPI, "DrawingAPI cannot be null");
this.x = x;
this.y = y;
this.color = color != null ? color : Color.BLACK;
}
public abstract void draw();
public abstract double getArea();
public void move(double deltaX, double deltaY) {
this.x += deltaX;
this.y += deltaY;
}
public void setColor(Color color) {
this.color = color != null ? color : Color.BLACK;
}
public String getApiName() {
return drawingAPI.getApiName();
}
}
// 圆形实现
public class Circle extends Shape {
private double radius;
public Circle(DrawingAPI drawingAPI, double x, double y, double radius, Color color) {
super(drawingAPI, x, y, color);
this.radius = Math.max(0, radius);
}
@Override
public void draw() {
drawingAPI.drawCircle(x, y, radius, color);
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
public void setRadius(double radius) {
this.radius = Math.max(0, radius);
}
public double getRadius() {
return radius;
}
}
// 矩形实现
public class Rectangle extends Shape {
private double width, height;
public Rectangle(DrawingAPI drawingAPI, double x, double y, double width, double height, Color color) {
super(drawingAPI, x, y, color);
this.width = Math.max(0, width);
this.height = Math.max(0, height);
}
@Override
public void draw() {
drawingAPI.drawRectangle(x, y, width, height, color);
}
@Override
public double getArea() {
return width * height;
}
public void setSize(double width, double height) {
this.width = Math.max(0, width);
this.height = Math.max(0, height);
}
public double getWidth() { return width; }
public double getHeight() { return height; }
}
// 客户端使用示例
public class BridgeClient {
public static void main(String[] args) {
// 消息推送系统示例
MessagePlatform aliyun = PlatformFactory.createAliyunPlatform();
Message smsMessage = MessageFactory.createSmsMessage(aliyun)
.setTitle("系统通知")
.setContent("您有一条新消息")
.addRecipient("13800138000")
.addRecipient("13900139000");
List<PushResult> results = smsMessage.send();
results.forEach(System.out::println);
// 绘图系统示例
DrawingAPI windowsAPI = new WindowsDrawingAPI();
DrawingAPI linuxAPI = new LinuxDrawingAPI();
Shape circle1 = new Circle(windowsAPI, 10, 10, 5, Color.RED);
Shape circle2 = new Circle(linuxAPI, 20, 20, 8, Color.BLUE);
System.out.println("绘制图形:");
circle1.draw();
circle2.draw();
System.out.printf("圆形1面积: %.2f (使用%s)%n", circle1.getArea(), circle1.getApiName());
System.out.printf("圆形2面积: %.2f (使用%s)%n", circle2.getArea(), circle2.getApiName());
}
// 总结:通过桥接模式,消息类型与推送平台、形状与绘图API实现了解耦,便于灵活扩展和组合。
}
7. 测试用例
业务背景: 验证桥接模式的核心功能,包括基本桥接功能、消息推送系统和绘图系统。
package com.example.patterns.bridge.test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
import java.awt.Color;
import java.util.List;
public class BridgePatternTest {
private MessagePlatform aliyunPlatform;
private MessagePlatform tencentPlatform;
private DrawingAPI windowsAPI;
private DrawingAPI linuxAPI;
@BeforeEach
public void setUp() {
aliyunPlatform = PlatformFactory.createAliyunPlatform();
tencentPlatform = PlatformFactory.createTencentPlatform();
windowsAPI = new WindowsDrawingAPI();
linuxAPI = new LinuxDrawingAPI();
}
@Test
public void testBasicBridgePattern() {
// 测试基本桥接模式
Implementor implA = new ConcreteImplementorA();
Implementor implB = new ConcreteImplementorB();
Abstraction abstractionA = new RefinedAbstraction(implA);
Abstraction abstractionB = new RefinedAbstraction(implB);
// 验证可以正常调用
assertDoesNotThrow(() -> {
abstractionA.operation();
abstractionB.operation();
});
// 验证实现类型正确
assertEquals("ImplementorA", abstractionA.getImplementorType());
assertEquals("ImplementorB", abstractionB.getImplementorType());
}
@Test
public void testAbstractionWithNullImplementor() {
// 测试空实现异常处理
assertThrows(NullPointerException.class, () -> {
new RefinedAbstraction(null);
});
}
@Test
public void testSmsMessageSending() {
// 测试短信消息发送
Message smsMessage = MessageFactory.createSmsMessage(aliyunPlatform)
.setTitle("测试通知")
.setContent("这是一条测试短信")
.addRecipient("13800138000")
.addRecipient("13900139000");
List<PushResult> results = smsMessage.send();
assertNotNull("发送结果不应为空", results);
assertEquals("应该有两条发送结果", 2, results.size());
for (PushResult result : results) {
assertTrue("发送应该成功", result.isSuccess());
assertEquals("平台应为阿里云", "阿里云", result.getPlatformName());
assertNotNull("消息ID不应为空", result.getMessageId());
assertTrue("消息ID应以aliyun开头", result.getMessageId().startsWith("aliyun_"));
}
}
@Test
public void testEmailMessageSending() {
// 测试邮件消息发送
Message emailMessage = MessageFactory.createEmailMessage(tencentPlatform)
.setTitle("重要通知")
.setContent("这是一封重要邮件")
.addRecipient("test@example.com")
.addMetadata("priority", "high");
List<PushResult> results = emailMessage.send();
assertNotNull("发送结果不应为空", results);
assertEquals("应该有一条发送结果", 1, results.size());
PushResult result = results.get(0);
assertTrue("发送应该成功", result.isSuccess());
assertEquals("平台应为腾讯云", "腾讯云", result.getPlatformName());
assertNotNull("时间戳不应为空", result.getTimestamp());
}
@Test
public void testPushNotificationSending() {
// 测试推送通知发送
MessagePlatform huaweiPlatform = PlatformFactory.createHuaweiPlatform();
Message pushMessage = MessageFactory.createPushNotification(huaweiPlatform)
.setTitle("系统更新")
.setContent("新版本已可用")
.addRecipient("user123")
.addMetadata("action", "update");
List<PushResult> results = pushMessage.send();
assertNotNull("发送结果不应为空", results);
assertEquals("应该有一条发送结果", 1, results.size());
PushResult result = results.get(0);
assertTrue("发送应该成功", result.isSuccess());
assertEquals("平台应为华为云", "华为云", result.getPlatformName());
assertTrue("消息ID应以huawei开头", result.getMessageId().startsWith("huawei_"));
}
@Test
public void testMessageWithUnavailablePlatform() {
// 测试平台不可用时的处理
AliyunMessagePlatform aliyun = new AliyunMessagePlatform();
aliyun.setAvailable(false);
Message smsMessage = MessageFactory.createSmsMessage(aliyun)
.setContent("测试消息")
.addRecipient("13800138000");
List<PushResult> results = smsMessage.send();
assertNotNull("发送结果不应为空", results);
assertEquals("应该有一条发送结果", 1, results.size());
PushResult result = results.get(0);
assertFalse("发送应该失败", result.isSuccess());
assertEquals("错误信息应正确", "阿里云平台暂不可用", result.getErrorMessage());
}
@Test
public void testMessageWithNullPlatform() {
// 测试空平台异常处理
assertThrows(NullPointerException.class, () -> {
MessageFactory.createSmsMessage(null);
});
}
@Test
public void testMessageBuilderPattern() {
// 测试消息构建器模式
Message message = MessageFactory.createSmsMessage(aliyunPlatform)
.setTitle("测试")
.setContent("内容")
.addRecipient("13800138000")
.addRecipient("") // 空接收者应被忽略
.addRecipient(null) // null接收者应被忽略
.addMetadata("key1", "value1")
.addMetadata("key2", "value2");
List<PushResult> results = message.send();
// 应该只有一条有效的接收者
assertEquals("应该只有一条发送结果", 1, results.size());
}
@Test
public void testCircleDrawing() {
// 测试圆形绘制
Shape circle1 = new Circle(windowsAPI, 10, 10, 5, Color.RED);
Shape circle2 = new Circle(linuxAPI, 20, 20, 8, Color.BLUE);
// 验证可以正常绘制
assertDoesNotThrow(() -> {
circle1.draw();
circle2.draw();
});
// 验证API名称
assertEquals("Windows GDI", circle1.getApiName());
assertEquals("Linux X11", circle2.getApiName());
// 验证面积计算
assertEquals(Math.PI * 25, circle1.getArea(), 0.001);
assertEquals(Math.PI * 64, circle2.getArea(), 0.001);
}
@Test
public void testRectangleDrawing() {
// 测试矩形绘制
Shape rect1 = new Rectangle(windowsAPI, 0, 0, 10, 20, Color.GREEN);
Shape rect2 = new Rectangle(linuxAPI, 5, 5, 15, 25, Color.YELLOW);
// 验证可以正常绘制
assertDoesNotThrow(() -> {
rect1.draw();
rect2.draw();
});
// 验证面积计算
assertEquals(200, rect1.getArea(), 0.001);
assertEquals(375, rect2.getArea(), 0.001);
}
@Test
public void testShapeWithNullAPI() {
// 测试空绘图API异常处理
assertThrows(NullPointerException.class, () -> {
new Circle(null, 0, 0, 5, Color.RED);
});
assertThrows(NullPointerException.class, () -> {
new Rectangle(null, 0, 0, 10, 20, Color.BLUE);
});
}
@Test
public void testShapeMovement() {
// 测试形状移动
Circle circle = new Circle(windowsAPI, 10, 10, 5, Color.RED);
circle.move(5, 3);
// 注意:这里我们无法直接验证移动结果,因为x,y是protected
// 在实际项目中,可以添加getter方法或测试绘制输出
assertDoesNotThrow(() -> circle.draw());
}
@Test
public void testShapeColorChange() {
// 测试形状颜色变更
Circle circle = new Circle(windowsAPI, 10, 10, 5, Color.RED);
circle.setColor(Color.BLUE);
circle.setColor(null); // 应设置为默认黑色
assertDoesNotThrow(() -> circle.draw());
}
@Test
public void testCircleRadiusValidation() {
// 测试圆形半径验证
Circle circle = new Circle(windowsAPI, 0, 0, -5, Color.RED);
// 负半径应被修正为0
assertEquals(0, circle.getRadius(), 0.001);
circle.setRadius(10);
assertEquals(10, circle.getRadius(), 0.001);
circle.setRadius(-3); // 应被修正为0
assertEquals(0, circle.getRadius(), 0.001);
}
@Test
public void testRectangleSizeValidation() {
// 测试矩形尺寸验证
Rectangle rect = new Rectangle(windowsAPI, 0, 0, -10, -20, Color.BLUE);
// 负尺寸应被修正为0
assertEquals(0, rect.getWidth(), 0.001);
assertEquals(0, rect.getHeight(), 0.001);
assertEquals(0, rect.getArea(), 0.001);
rect.setSize(15, 25);
assertEquals(15, rect.getWidth(), 0.001);
assertEquals(25, rect.getHeight(), 0.001);
assertEquals(375, rect.getArea(), 0.001);
}
@Test
public void testMessageFactoryCreation() {
// 测试消息工厂创建
Message sms = MessageFactory.createSmsMessage(aliyunPlatform);
Message email = MessageFactory.createEmailMessage(aliyunPlatform);
Message push = MessageFactory.createPushNotification(aliyunPlatform);
assertTrue("应创建短信消息", sms instanceof SmsMessage);
assertTrue("应创建邮件消息", email instanceof EmailMessage);
assertTrue("应创建推送通知", push instanceof PushNotification);
}
@Test
public void testPlatformFactoryCreation() {
// 测试平台工厂创建
MessagePlatform aliyun = PlatformFactory.createAliyunPlatform();
MessagePlatform tencent = PlatformFactory.createTencentPlatform();
MessagePlatform huawei = PlatformFactory.createHuaweiPlatform();
assertTrue("应创建阿里云平台", aliyun instanceof AliyunMessagePlatform);
assertTrue("应创建腾讯云平台", tencent instanceof TencentMessagePlatform);
assertTrue("应创建华为云平台", huawei instanceof HuaweiMessagePlatform);
assertEquals("阿里云", aliyun.getPlatformName());
assertEquals("腾讯云", tencent.getPlatformName());
assertEquals("华为云", huawei.getPlatformName());
}
@Test
public void testPushResultToString() {
// 测试推送结果字符串表示
PushResult result = new PushResult(true, "test123", "阿里云", null);
String resultString = result.toString();
assertNotNull("字符串表示不应为空", resultString);
assertTrue("应包含成功状态", resultString.contains("success=true"));
assertTrue("应包含消息ID", resultString.contains("messageId='test123'"));
assertTrue("应包含平台名称", resultString.contains("platform='阿里云'"));
}
}
8. 常见误区与反例
8.1 常见误区
误区1 :过度使用桥接模式
// 错误示例:为简单功能滥用桥接模式 public interface SimpleOperation { void doSomething(); } public class SimpleImplementation implements SimpleOperation { public void doSomething() { System.out.println("简单操作"); } } // 不必要的抽象层 public abstract class UnnecessaryAbstraction { protected SimpleOperation operation; public UnnecessaryAbstraction(SimpleOperation operation) { this.operation = operation; } public abstract void execute(); }
正确做法:只在真正需要多维度扩展时使用桥接模式。
误区2 :抽象与实现边界不清
// 错误示例:抽象层包含具体实现逻辑 public class BadAbstraction { private Implementation impl; public void operation() { // 错误:在抽象层处理具体业务逻辑 validateInput(); logOperation(); impl.doWork(); updateDatabase(); } }
正确做法:抽象层只做接口转换,具体逻辑放在实现层。
误区3 :忽略运行时切换的线程安全
// 错误示例:非线程安全的实现切换 public class UnsafeAbstraction { private Implementation impl; public void setImplementation(Implementation impl) { this.impl = impl; // 可能导致并发问题 } }
8.2 反例分析
反例1 :硬编码实现选择
在抽象层中硬编码选择具体实现,失去了桥接模式的灵活性。反例2 :实现层相互依赖
不同实现之间存在耦合,违反了桥接模式的解耦原则。反例3 :抽象层过于复杂
抽象层包含过多业务逻辑,模糊了抽象与实现的边界。
9. 最佳实践
9.1 设计原则
清晰的职责分离 :明确抽象和实现的边界
// 推荐:清晰的职责分离 public abstract class PaymentProcessor { protected final PaymentGateway gateway; public PaymentProcessor(PaymentGateway gateway) { this.gateway = Objects.requireNonNull(gateway); } // 抽象层负责流程控制 public final PaymentResult process(PaymentRequest request) { validateRequest(request); return doProcess(request); } protected abstract PaymentResult doProcess(PaymentRequest request); protected abstract void validateRequest(PaymentRequest request); }
接口设计要稳定 :实现接口应保持向后兼容
// 推荐:版本化接口设计 public interface PaymentGateway { PaymentResult processPayment(PaymentRequest request); // 扩展方法,保持向后兼容 default PaymentResult processPayment(PaymentRequest request, PaymentOptions options) { return processPayment(request); } String getGatewayVersion(); }
9.2 实现技巧
使用工厂模式创建桥接 :简化客户端使用
// 推荐:桥接工厂 public class MessageBridgeFactory { private static final Map<String, MessagePlatform> PLATFORMS = new ConcurrentHashMap<>(); static { PLATFORMS.put("aliyun", new AliyunMessagePlatform()); PLATFORMS.put("tencent", new TencentMessagePlatform()); PLATFORMS.put("huawei", new HuaweiMessagePlatform()); } public static Message createMessage(String type, String platform) { MessagePlatform platformImpl = PLATFORMS.get(platform); if (platformImpl == null) { throw new IllegalArgumentException("Unsupported platform: " + platform); } return MessageFactory.createMessage(type, platformImpl); } }
支持运行时切换 :提供安全的实现切换机制
// 推荐:线程安全的实现切换 public class SwitchableProcessor { private volatile Implementation impl; private final ReadWriteLock lock = new ReentrantReadWriteLock(); public void switchImplementation(Implementation newImpl) { lock.writeLock().lock(); try { this.impl = Objects.requireNonNull(newImpl); } finally { lock.writeLock().unlock(); } } public void process() { lock.readLock().lock(); try { impl.doWork(); } finally { lock.readLock().unlock(); } } }
配置化实现选择 :通过配置管理实现选择
// 推荐:配置化桥接 @Component public class ConfigurableBridge { @Value("${bridge.implementation.type:default}") private String implementationType; @Autowired private Map<String, Implementation> implementations; @PostConstruct public void init() { Implementation impl = implementations.get(implementationType); if (impl == null) { throw new IllegalStateException("No implementation found for type: " + implementationType); } setImplementation(impl); } }
9.3 性能优化
缓存策略 :合理使用缓存提升性能
// 推荐:带缓存的桥接实现 public class CachedMessageBridge { private final MessagePlatform platform; private final Cache<String, MessageTemplate> templateCache; public CachedMessageBridge(MessagePlatform platform) { this.platform = platform; this.templateCache = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(Duration.ofMinutes(30)) .build(); } public PushResult sendTemplateMessage(String templateId, Map<String, Object> params) { MessageTemplate template = templateCache.get(templateId, key -> platform.getTemplate(key)); return platform.sendMessage(template.format(params)); } }
异步处理 :支持异步操作提升吞吐量
// 推荐:异步桥接实现 public class AsyncMessageBridge { private final MessagePlatform platform; private final Executor executor; public CompletableFuture<PushResult> sendMessageAsync(Message message) { return CompletableFuture.supplyAsync(() -> { try { return platform.sendMessage(message); } catch (Exception e) { return new PushResult(false, null, platform.getPlatformName(), e.getMessage()); } }, executor); } }
9.4 架构考虑
监控和日志 :完善的观察性支持
// 推荐:带监控的桥接实现 public class MonitoredBridge { private static final Logger log = LoggerFactory.getLogger(MonitoredBridge.class); private final MeterRegistry meterRegistry; private final Implementation impl; public void process(Request request) { Timer.Sample sample = Timer.start(meterRegistry); String implType = impl.getClass().getSimpleName(); try { log.debug("Processing request with implementation: {}", implType); impl.doWork(request); meterRegistry.counter("bridge.success", "impl", implType).increment(); } catch (Exception e) { log.error("Bridge processing failed with implementation: {}", implType, e); meterRegistry.counter("bridge.error", "impl", implType).increment(); throw e; } finally { sample.stop(Timer.builder("bridge.duration") .tag("impl", implType) .register(meterRegistry)); } } }
扩展点设计 :提供灵活的扩展机制
// 推荐:可扩展的桥接设计 public abstract class ExtensibleBridge { protected final List<BridgeInterceptor> interceptors = new ArrayList<>(); protected final Implementation impl; public void addInterceptor(BridgeInterceptor interceptor) { interceptors.add(interceptor); } protected final void process(Request request) { // 前置处理 interceptors.forEach(i -> i.beforeProcess(request)); try { doProcess(request); // 后置处理 interceptors.forEach(i -> i.afterProcess(request)); } catch (Exception e) { // 异常处理 interceptors.forEach(i -> i.onError(request, e)); throw e; } } protected abstract void doProcess(Request request); }
版本兼容性 :支持多版本实现共存
// 推荐:版本感知的桥接 public class VersionAwareBridge { private final Map<String, Implementation> implementations; public void process(Request request) { String version = request.getVersion(); Implementation impl = implementations.get(version); if (impl == null) { // 降级到默认版本 impl = implementations.get("default"); } if (impl == null) { throw new UnsupportedOperationException("No implementation for version: " + version); } impl.process(request); } }
10. 参考资料与延伸阅读
- 《设计模式:可复用面向对象软件的基础》GoF
- Effective Java(中文版)
- https://refactoringguru.cn/design-patterns/bridge
- https://www.baeldung.com/java-bridge-pattern
本文为设计模式系列第10篇,后续每篇将聚焦一个设计模式或设计原则,深入讲解实现与应用,敬请关注。