在软件开发的世界中,变化是唯一的常量。需求变更、功能扩展、技术迭代不断挑战着我们的代码设计。一个缺乏灵活性的系统往往会在这些变化面前显得脆弱,导致大量的重构工作和潜在的Bug。设计模式作为经验总结,为我们提供了应对这些挑战的有效工具。
本文将通过实际项目案例,展示如何运用设计模式解决软件灵活性问题,并提供切实可行的代码实现。
案例一:支付系统的扩展性挑战
问题背景
假设我们正在开发一个电子商务平台,最初只支持支付宝和微信支付。随着业务发展,需要不断接入新的支付方式,如银联、PayPal等。同时,每种支付方式的处理逻辑、参数要求和回调处理都不同。
最初的实现(有问题的方案)
许多开发者最初可能会使用条件语句来处理不同支付方式:
public class PaymentService {
public void processPayment(String paymentType, double amount, String orderId) {
if ("alipay".equals(paymentType)) {
// 处理支付宝支付
System.out.println("使用支付宝支付 " + amount + " 元,订单号: " + orderId);
// 调用支付宝API
} else if ("wechat".equals(paymentType)) {
// 处理微信支付
System.out.println("使用微信支付 " + amount + " 元,订单号: " + orderId);
// 调用微信API
}
// 未来添加更多支付方式...
}
public void handleCallback(String paymentType, Map<String, String> callbackData) {
if ("alipay".equals(paymentType)) {
// 处理支付宝回调
String tradeStatus = callbackData.get("trade_status");
if ("TRADE_SUCCESS".equals(tradeStatus)) {
// 更新订单状态
}
} else if ("wechat".equals(paymentType)) {
// 处理微信回调
String returnCode = callbackData.get("return_code");
if ("SUCCESS".equals(returnCode)) {
// 更新订单状态
}
}
// 未来添加更多回调处理...
}
}
问题分析:
- 违反开闭原则:每次添加新支付方式,都需要修改核心业务逻辑,增加if-else分支
- 职责过于集中:一个类负责所有支付方式的处理
- 代码膨胀:随着支付方式增加,方法体会变得臃肿难以维护
- 测试困难:添加新的支付方式可能影响现有功能
使用策略模式和工厂模式的解决方案
我们可以结合策略模式和工厂模式来重构支付系统:
// 策略接口
interface PaymentStrategy {
void processPayment(double amount, String orderId);
boolean handleCallback(Map<String, String> callbackData);
}
// 具体策略:支付宝
class AlipayStrategy implements PaymentStrategy {
@Override
public void processPayment(double amount, String orderId) {
System.out.println("使用支付宝支付 " + amount + " 元,订单号: " + orderId);
// 调用支付宝API
}
@Override
public boolean handleCallback(Map<String, String> callbackData) {
String tradeStatus = callbackData.get("trade_status");
if ("TRADE_SUCCESS".equals(tradeStatus)) {
// 更新订单状态
return true;
}
return false;
}
}
// 具体策略:微信支付
class WechatPayStrategy implements PaymentStrategy {
@Override
public void processPayment(double amount, String orderId) {
System.out.println("使用微信支付 " + amount + " 元,订单号: " + orderId);
// 调用微信API
}
@Override
public boolean handleCallback(Map<String, String> callbackData) {
String returnCode = callbackData.get("return_code");
if ("SUCCESS".equals(returnCode)) {
// 更新订单状态
return true;
}
return false;
}
}
// 工厂类
class PaymentStrategyFactory {
private static final Map<String, PaymentStrategy> STRATEGIES = new HashMap<>();
static {
STRATEGIES.put("alipay", new AlipayStrategy());
STRATEGIES.put("wechat", new WechatPayStrategy());
}
public static PaymentStrategy getStrategy(String paymentType) {
return STRATEGIES.get(paymentType);
}
// 支持动态注册策略
public static void registerStrategy(String paymentType, PaymentStrategy strategy) {
STRATEGIES.put(paymentType, strategy);
}
}
// 上下文类
class PaymentService {
public void processPayment(String paymentType, double amount, String orderId) {
PaymentStrategy strategy = PaymentStrategyFactory.getStrategy(paymentType);
if (strategy == null) {
throw new IllegalArgumentException("Unsupported payment type: " + paymentType);
}
strategy.processPayment(amount, orderId);
}
public boolean handleCallback(String paymentType, Map<String, String> callbackData) {
PaymentStrategy strategy = PaymentStrategyFactory.getStrategy(paymentType);
if (strategy == null) {
throw new IllegalArgumentException("Unsupported payment type: " + paymentType);
}
return strategy.handleCallback(callbackData);
}
}
新的支付方式接入示例:
// 具体策略:银联支付
class UnionPayStrategy implements PaymentStrategy {
@Override
public void processPayment(double amount, String orderId) {
System.out.println("使用银联支付 " + amount + " 元,订单号: " + orderId);
// 调用银联API
}
@Override
public boolean handleCallback(Map<String, String> callbackData) {
String respCode = callbackData.get("respCode");
if ("00".equals(respCode)) {
// 更新订单状态
return true;
}
return false;
}
}
// 注册新的支付方式
PaymentStrategyFactory.registerStrategy("unionpay", new UnionPayStrategy());
优势分析:
- 开闭原则:添加新支付方式无需修改现有代码,只需创建新的策略类并注册
- 单一职责:每个策略类只负责一种支付方式
- 代码解耦:支付类型和处理逻辑解耦
- 易于测试:可以独立测试每种支付策略
- 运行时灵活性:支持动态注册新的支付方式
案例二:通知系统的管理和扩展
问题背景
假设我们正在构建一个电商平台的通知系统,需要在特定事件发生(如订单状态变更、库存预警)时通知相关人员。最初可能只有邮件通知,但随着系统发展,需要增加短信、App推送、微信消息等多种通知方式。
初始实现(有问题的方案)
public class OrderService {
private EmailService emailService;
private SMSService smsService;
public OrderService() {
this.emailService = new EmailService();
this.smsService = new SMSService();
}
public void updateOrderStatus(Order order, OrderStatus newStatus) {
// 更新订单状态
order.setStatus(newStatus);
// 发送通知
if (newStatus == OrderStatus.PAID) {
// 通知商家
emailService.sendEmail(order.getSellerEmail(), "订单已支付",
"订单 " + order.getId() + " 已支付,请尽快处理。");
// 通知买家
smsService.sendSMS(order.getBuyerPhone(),
"您的订单 " + order.getId() + " 已支付,我们会尽快处理。");
}
else if (newStatus == OrderStatus.SHIPPED) {
// 通知买家
emailService.sendEmail(order.getBuyerEmail(), "订单已发货",
"订单 " + order.getId() + " 已发货,物流单号: " + order.getTrackingNumber());
smsService.sendSMS(order.getBuyerPhone(),
"您的订单 " + order.getId() + " 已发货,物流单号: " + order.getTrackingNumber());
}
// 其他状态处理...
}
}
问题分析:
- 强耦合:业务逻辑与通知机制紧密耦合
- 难以扩展:增加新的通知方式需要修改业务代码
- 重复代码:每个状态变更处重复编写通知逻辑
- 不易配置:无法灵活配置特定状态下使用何种通知方式
使用观察者模式的解决方案
// 事件类
class OrderEvent {
private Order order;
private OrderStatus oldStatus;
private OrderStatus newStatus;
// 构造器、getter等
public OrderEvent(Order order, OrderStatus oldStatus, OrderStatus newStatus) {
this.order = order;
this.oldStatus = oldStatus;
this.newStatus = newStatus;
}
public Order getOrder() { return order; }
public OrderStatus getOldStatus() { return oldStatus; }
public OrderStatus getNewStatus() { return newStatus; }
}
// 观察者接口
interface OrderEventObserver {
void onOrderStatusChanged(OrderEvent event);
}
// 具体观察者:邮件通知
class EmailNotifier implements OrderEventObserver {
private EmailService emailService = new EmailService();
@Override
public void onOrderStatusChanged(OrderEvent event) {
Order order = event.getOrder();
OrderStatus newStatus = event.getNewStatus();
if (newStatus == OrderStatus.PAID) {
// 通知商家
emailService.sendEmail(order.getSellerEmail(), "订单已支付",
"订单 " + order.getId() + " 已支付,请尽快处理。");
}
else if (newStatus == OrderStatus.SHIPPED) {
// 通知买家
emailService.sendEmail(order.getBuyerEmail(), "订单已发货",
"订单 " + order.getId() + " 已发货,物流单号: " + order.getTrackingNumber());
}
}
}
// 具体观察者:短信通知
class SMSNotifier implements OrderEventObserver {
private SMSService smsService = new SMSService();
@Override
public void onOrderStatusChanged(OrderEvent event) {
Order order = event.getOrder();
OrderStatus newStatus = event.getNewStatus();
if (newStatus == OrderStatus.PAID) {
// 通知买家
smsService.sendSMS(order.getBuyerPhone(),
"您的订单 " + order.getId() + " 已支付,我们会尽快处理。");
}
else if (newStatus == OrderStatus.SHIPPED) {
// 通知买家
smsService.sendSMS(order.getBuyerPhone(),
"您的订单 " + order.getId() + " 已发货,物流单号: " + order.getTrackingNumber());
}
}
}
// 主题类:事件发布者
class OrderEventPublisher {
private List<OrderEventObserver> observers = new ArrayList<>();
public void addObserver(OrderEventObserver observer) {
observers.add(observer);
}
public void removeObserver(OrderEventObserver observer) {
observers.remove(observer);
}
public void publishEvent(OrderEvent event) {
for (OrderEventObserver observer : observers) {
observer.onOrderStatusChanged(event);
}
}
}
// 改进后的订单服务
class OrderService {
private OrderEventPublisher eventPublisher;
public OrderService() {
this.eventPublisher = new OrderEventPublisher();
// 注册观察者
this.eventPublisher.addObserver(new EmailNotifier());
this.eventPublisher.addObserver(new SMSNotifier());
}
public void updateOrderStatus(Order order, OrderStatus newStatus) {
OrderStatus oldStatus = order.getStatus();
// 更新订单状态
order.setStatus(newStatus);
// 发布事件
OrderEvent event = new OrderEvent(order, oldStatus, newStatus);
eventPublisher.publishEvent(event);
}
}
添加新的通知方式:
// 具体观察者:App推送通知
class AppPushNotifier implements OrderEventObserver {
private AppPushService pushService = new AppPushService();
@Override
public void onOrderStatusChanged(OrderEvent event) {
Order order = event.getOrder();
OrderStatus newStatus = event.getNewStatus();
if (newStatus == OrderStatus.SHIPPED) {
// 通知买家
pushService.sendPushNotification(order.getBuyerId(),
"订单发货", "您的订单 " + order.getId() + " 已发货");
}
}
}
// 注册新的观察者
orderService.getEventPublisher().addObserver(new AppPushNotifier());
优势分析:
- 松耦合:业务逻辑与通知实现分离
- 易于扩展:添加新的通知方式只需创建新的观察者并注册
- 集中管理:通知逻辑集中在各自的观察者类中
- 运行时配置:可在运行时动态添加或移除通知方式
案例三:报表导出功能的灵活扩展
问题背景
假设我们的系统需要支持多种格式的报表导出功能,如CSV、Excel、PDF等。随着需求发展,不仅需要支持更多导出格式,还需要为不同格式提供自定义选项。
初始实现(有问题的方案)
public class ReportExporter {
public void exportReport(String format, ReportData data, String filePath) throws IOException {
if ("csv".equalsIgnoreCase(format)) {
// 导出CSV
try (FileWriter writer = new FileWriter(filePath)) {
// 写入表头
writer.write(String.join(",", data.getHeaders()) + "\n");
// 写入数据行
for (List<String> row : data.getRows()) {
writer.write(String.join(",", row) + "\n");
}
}
}
else if ("excel".equalsIgnoreCase(format)) {
// 导出Excel
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Report");
// 创建表头
Row headerRow = sheet.createRow(0);
List<String> headers = data.getHeaders();
for (int i = 0; i < headers.size(); i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers.get(i));
}
// 创建数据行
List<List<String>> dataRows = data.getRows();
for (int i = 0; i < dataRows.size(); i++) {
Row row = sheet.createRow(i + 1);
List<String> rowData = dataRows.get(i);
for (int j = 0; j < rowData.size(); j++) {
Cell cell = row.createCell(j);
cell.setCellValue(rowData.get(j));
}
}
// 保存文件
try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
workbook.write(fileOut);
}
workbook.close();
}
// 其他格式...
}
}
问题分析:
- 代码重复:每种格式的处理逻辑都在同一个方法中
- 难以维护:方法体过长,逻辑复杂
- 扩展性差:添加新格式需要修改现有代码
- 功能限制:难以为不同格式提供自定义选项
使用模板方法模式和装饰器模式的解决方案
首先使用模板方法模式抽象出导出流程:
// 抽象导出器基类
abstract class ReportExporter {
// 模板方法,定义导出流程的骨架
public final void export(ReportData data, String filePath) throws IOException {
prepareExport(data);
writeHeaders(data.getHeaders(), filePath);
writeData(data.getRows(), filePath);
finalizeExport(filePath);
}
// 钩子方法,可以被子类重写
protected void prepareExport(ReportData data) throws IOException {
// 默认实现为空
}
// 抽象方法,必须由子类实现
protected abstract void writeHeaders(List<String> headers, String filePath) throws IOException;
protected abstract void writeData(List<List<String>> rows, String filePath) throws IOException;
// 钩子方法,可以被子类重写
protected void finalizeExport(String filePath) throws IOException {
// 默认实现为空
}
}
// CSV导出器
class CsvExporter extends ReportExporter {
private FileWriter writer;
@Override
protected void prepareExport(ReportData data) throws IOException {
writer = new FileWriter(filePath);
}
@Override
protected void writeHeaders(List<String> headers, String filePath) throws IOException {
writer.write(String.join(",", headers) + "\n");
}
@Override
protected void writeData(List<List<String>> rows, String filePath) throws IOException {
for (List<String> row : rows) {
writer.write(String.join(",", row) + "\n");
}
}
@Override
protected void finalizeExport(String filePath) throws IOException {
if (writer != null) {
writer.close();
}
}
}
// Excel导出器
class ExcelExporter extends ReportExporter {
private Workbook workbook;
private Sheet sheet;
private int rowIndex;
@Override
protected void prepareExport(ReportData data) {
workbook = new XSSFWorkbook();
sheet = workbook.createSheet("Report");
rowIndex = 0;
}
@Override
protected void writeHeaders(List<String> headers, String filePath) {
Row headerRow = sheet.createRow(rowIndex++);
for (int i = 0; i < headers.size(); i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers.get(i));
}
}
@Override
protected void writeData(List<List<String>> rows, String filePath) {
for (List<String> rowData : rows) {
Row row = sheet.createRow(rowIndex++);
for (int i = 0; i < rowData.size(); i++) {
Cell cell = row.createCell(i);
cell.setCellValue(rowData.get(i));
}
}
}
@Override
protected void finalizeExport(String filePath) throws IOException {
try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
workbook.write(fileOut);
}
workbook.close();
}
}
然后使用工厂方法创建导出器:
// 导出器工厂
class ReportExporterFactory {
public static ReportExporter createExporter(String format) {
if ("csv".equalsIgnoreCase(format)) {
return new CsvExporter();
} else if ("excel".equalsIgnoreCase(format)) {
return new ExcelExporter();
} else if ("pdf".equalsIgnoreCase(format)) {
return new PdfExporter();
}
throw new IllegalArgumentException("Unsupported format: " + format);
}
}
最后,使用装饰器模式为导出器添加额外功能:
// 导出器装饰器基类
abstract class ReportExporterDecorator extends ReportExporter {
protected ReportExporter decoratedExporter;
public ReportExporterDecorator(ReportExporter exporter) {
this.decoratedExporter = exporter;
}
}
// 加密装饰器
class EncryptedExporterDecorator extends ReportExporterDecorator {
private String password;
public EncryptedExporterDecorator(ReportExporter exporter, String password) {
super(exporter);
this.password = password;
}
@Override
protected void prepareExport(ReportData data) throws IOException {
decoratedExporter.prepareExport(data);
}
@Override
protected void writeHeaders(List<String> headers, String filePath) throws IOException {
decoratedExporter.writeHeaders(headers, filePath);
}
@Override
protected void writeData(List<List<String>> rows, String filePath) throws IOException {
decoratedExporter.writeData(rows, filePath);
}
@Override
protected void finalizeExport(String filePath) throws IOException {
decoratedExporter.finalizeExport(filePath);
// 加密文件
encryptFile(filePath, password);
}
private void encryptFile(String filePath, String password) {
System.out.println("使用密码 " + password + " 加密文件 " + filePath);
// 实际加密逻辑
}
}
// 压缩装饰器
class CompressedExporterDecorator extends ReportExporterDecorator {
public CompressedExporterDecorator(ReportExporter exporter) {
super(exporter);
}
@Override
protected void prepareExport(ReportData data) throws IOException {
decoratedExporter.prepareExport(data);
}
@Override
protected void writeHeaders(List<String> headers, String filePath) throws IOException {
decoratedExporter.writeHeaders(headers, filePath);
}
@Override
protected void writeData(List<List<String>> rows, String filePath) throws IOException {
decoratedExporter.writeData(rows, filePath);
}
@Override
protected void finalizeExport(String filePath) throws IOException {
decoratedExporter.finalizeExport(filePath);
// 压缩文件
compressFile(filePath);
}
private void compressFile(String filePath) {
System.out.println("压缩文件 " + filePath);
// 实际压缩逻辑
}
}
使用示例:
// 客户端代码
public void generateReport(ReportData data, String format, String filePath,
boolean compress, boolean encrypt, String password) throws IOException {
// 创建基础导出器
ReportExporter exporter = ReportExporterFactory.createExporter(format);
// 按需应用装饰器
if (compress) {
exporter = new CompressedExporterDecorator(exporter);
}
if (encrypt && password != null) {
exporter = new EncryptedExporterDecorator(exporter, password);
}
// 执行导出
exporter.export(data, filePath);
}
优势分析:
- 代码结构清晰:每种导出格式有自己的实现类
- 功能扩展灵活:可以动态组合多种功能(加密、压缩等)
- 符合开闭原则:添加新格式或新功能不需要修改现有代码
- 复用模板流程:统一的导出流程,减少重复代码
案例四:配置项动态加载与应用
问题背景
假设我们有一个系统需要支持多样化的配置项,这些配置可能来自不同来源(配置文件、数据库、远程服务等),并且需要支持运行时热更新,且不同组件需要响应配置变更。
初始实现(有问题的方案)
public class AppConfiguration {
private Properties properties;
public AppConfiguration() {
loadProperties();
}
private void loadProperties() {
properties = new Properties();
try (FileInputStream fis = new FileInputStream("config.properties")) {
properties.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
}
public String getProperty(String key) {
return properties.getProperty(key);
}
public void reload() {
loadProperties();
// 手动通知各个组件
UserService userService = UserService.getInstance();
userService.updateCacheSize(Integer.parseInt(getProperty("user.cache.size")));
ProductService productService = ProductService.getInstance();
productService.setMaxProducts(Integer.parseInt(getProperty("product.max.count")));
// 更多组件...
}
}
// 使用配置的组件示例
class UserService {
private static UserService instance = new UserService();
private int cacheSize;
private UserService() {
// 初始化
}
public static UserService getInstance() {
return instance;
}
public void updateCacheSize(int newSize) {
this.cacheSize = newSize;
System.out.println("用户服务缓存大小更新为: " + newSize);
// 重置缓存等操作
}
}
问题分析:
- 强耦合:配置类直接引用了具体服务
- 难以扩展:添加新的配置源需要修改核心逻辑
- 代码重复:每个需要通知的组件都要手动编写通知代码
- 可维护性差:配置项增加时需要修改多处代码
使用观察者模式与适配器模式的解决方案
// 配置源接口
interface ConfigurationSource {
String getProperty(String key);
void load() throws IOException;
}
// 文件配置源
class PropertiesFileSource implements ConfigurationSource {
private Properties properties = new Properties();
private String filePath;
public PropertiesFileSource(String filePath) {
this.filePath = filePath;
}
@Override
public String getProperty(String key) {
return properties.getProperty(key);
}
@Override
public void load() throws IOException {
try (FileInputStream fis = new FileInputStream(filePath)) {
properties.load(fis);
}
}
}
// 数据库配置源
class DatabaseConfigSource implements ConfigurationSource {
private Map<String, String> configMap = new HashMap<>();
private DataSource dataSource;
public DatabaseConfigSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public String getProperty(String key) {
return configMap.get(key);
}
@Override
public void load() throws IOException {
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT key, value FROM app_config")) {
configMap.clear();
while (rs.next()) {
configMap.put(rs.getString("key"), rs.getString("value"));
}
} catch (SQLException e) {
throw new IOException("Failed to load configuration from database", e);
}
}
}
// 配置变更事件
class ConfigChangeEvent {
private String key;
private String oldValue;
private String newValue;
public ConfigChangeEvent(String key, String oldValue, String newValue) {
this.key = key;
this.oldValue = oldValue;
this.newValue = newValue;
}
// getters
public String getKey() { return key; }
public String getOldValue() { return oldValue; }
public String getNewValue() { return newValue; }
}
// 配置观察者接口
interface ConfigChangeListener {
void onConfigChanged(ConfigChangeEvent event);
}
// 配置管理核心类
class ConfigurationManager {
private Map<String, String> cachedConfig = new HashMap<>();
private List<ConfigurationSource> sources = new ArrayList<>();
private Map<String, List<ConfigChangeListener>> listeners = new HashMap<>();
public void addConfigurationSource(ConfigurationSource source) {
sources.add(source);
}
public void addEventListener(String key, ConfigChangeListener listener) {
listeners.computeIfAbsent(key, k -> new ArrayList<>()).add(listener);
}
public void removeEventListener(String key, ConfigChangeListener listener) {
if (listeners.containsKey(key)) {
listeners.get(key).remove(listener);
}
}
public String getProperty(String key) {
// 先查缓存
if (cachedConfig.containsKey(key)) {
return cachedConfig.get(key);
}
// 从各个源依次查找
for (ConfigurationSource source : sources) {
String value = source.getProperty(key);
if (value != null) {
cachedConfig.put(key, value);
return value;
}
}
return null;
}
public void reload() throws IOException {
// 保存旧配置用于比较
Map<String, String> oldConfig = new HashMap<>(cachedConfig);
// 清空缓存
cachedConfig.clear();
// 重新加载所有源
for (ConfigurationSource source : sources) {
source.load();
}
// 预加载关键配置项到缓存
for (String key : listeners.keySet()) {
String newValue = null;
for (ConfigurationSource source : sources) {
newValue = source.getProperty(key);
if (newValue != null) {
break;
}
}
if (newValue != null) {
cachedConfig.put(key, newValue);
}
}
// 通知所有监听器
for (Map.Entry<String, String> entry : cachedConfig.entrySet()) {
String key = entry.getKey();
String newValue = entry.getValue();
String oldValue = oldConfig.get(key);
// 如果值发生变化,触发事件
if (!Objects.equals(oldValue, newValue)) {
ConfigChangeEvent event = new ConfigChangeEvent(key, oldValue, newValue);
notifyListeners(key, event);
}
}
}
private void notifyListeners(String key, ConfigChangeEvent event) {
if (listeners.containsKey(key)) {
for (ConfigChangeListener listener : listeners.get(key)) {
listener.onConfigChanged(event);
}
}
}
}
// 组件配置监听示例
class UserServiceConfigListener implements ConfigChangeListener {
private UserService userService;
public UserServiceConfigListener(UserService userService) {
this.userService = userService;
}
@Override
public void onConfigChanged(ConfigChangeEvent event) {
if ("user.cache.size".equals(event.getKey())) {
try {
int newCacheSize = Integer.parseInt(event.getNewValue());
userService.updateCacheSize(newCacheSize);
} catch (NumberFormatException e) {
System.err.println("Invalid cache size value: " + event.getNewValue());
}
}
}
}
// 使用示例
public class ConfigurationExample {
public static void main(String[] args) throws IOException {
// 创建配置管理器
ConfigurationManager configManager = new ConfigurationManager();
// 添加配置源
configManager.addConfigurationSource(new PropertiesFileSource("config.properties"));
configManager.addConfigurationSource(new DatabaseConfigSource(dataSource));
// 初始化服务
UserService userService = new UserService();
ProductService productService = new ProductService();
// 注册配置监听器
configManager.addEventListener("user.cache.size", new UserServiceConfigListener(userService));
configManager.addEventListener("product.max.count", event -> {
try {
int maxProducts = Integer.parseInt(event.getNewValue());
productService.setMaxProducts(maxProducts);
} catch (NumberFormatException e) {
System.err.println("Invalid max products value: " + event.getNewValue());
}
});
// 初始加载配置
configManager.reload();
// 模拟配置变更
// ... 修改配置文件或数据库中的配置 ...
configManager.reload();
}
}
优势分析:
- 松耦合:配置管理器不直接依赖具体服务
- 可扩展:易于添加新的配置源或监听器
- 响应式更新:配置变更自动通知相关组件
- 优化性能:通过缓存减少配置查询开销
- 集中管理:统一的配置访问接口
案例五:插件系统的动态加载与扩展
问题背景
假设我们正在开发一个图像处理应用,需要支持各种滤镜和效果,这些功能需要以插件形式动态加载,便于第三方开发者扩展。
初始实现(有问题的方案)
public class ImageProcessor {
// 内置滤镜
public BufferedImage applyGrayscale(BufferedImage image) {
BufferedImage result = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
int gray = (r + g + b) / 3;
int newRgb = (gray << 16) + (gray << 8) + gray;
result.setRGB(x, y, newRgb);
}
}
return result;
}
public BufferedImage applySharpen(BufferedImage image) {
// 锐化实现...
return sharpenedImage;
}
public BufferedImage applyBlur(BufferedImage image) {
// 模糊实现...
return blurredImage;
}
// 更多滤镜...
}
问题分析:
- 代码膨胀:每增加一个滤镜,类就要膨胀
- 无法动态加载:新功能需要重新编译和部署整个应用
- 无法扩展:第三方无法添加自定义滤镜
- 测试困难:每次添加新滤镜都可能影响其他代码
使用组合模式、桥接模式和插件加载器解决方案
// 滤镜接口
interface ImageFilter {
String getName();
String getDescription();
BufferedImage apply(BufferedImage image);
}
// 具体滤镜实现:灰度
class GrayscaleFilter implements ImageFilter {
@Override
public String getName() {
return "Grayscale";
}
@Override
public String getDescription() {
return "将图像转换为灰度";
}
@Override
public BufferedImage apply(BufferedImage image) {
BufferedImage result = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
int gray = (r + g + b) / 3;
int newRgb = (gray << 16) + (gray << 8) + gray;
result.setRGB(x, y, newRgb);
}
}
return result;
}
}
// 组合滤镜(允许将多个滤镜组合使用)
class CompositeFilter implements ImageFilter {
private List<ImageFilter> filters = new ArrayList<>();
private String name;
private String description;
public CompositeFilter(String name, String description) {
this.name = name;
this.description = description;
}
public void addFilter(ImageFilter filter) {
filters.add(filter);
}
public void removeFilter(ImageFilter filter) {
filters.remove(filter);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public BufferedImage apply(BufferedImage image) {
BufferedImage result = image;
for (ImageFilter filter : filters) {
result = filter.apply(result);
}
return result;
}
}
// 插件管理器
class PluginManager {
private Map<String, ImageFilter> filters = new HashMap<>();
public void registerFilter(ImageFilter filter) {
filters.put(filter.getName(), filter);
System.out.println("注册滤镜: " + filter.getName());
}
public ImageFilter getFilter(String name) {
return filters.get(name);
}
public List<ImageFilter> getAllFilters() {
return new ArrayList<>(filters.values());
}
// 动态加载外部插件
public void loadPlugins(String pluginDir) throws Exception {
File dir = new File(pluginDir);
if (!dir.exists() || !dir.isDirectory()) {
return;
}
// 获取所有jar文件
File[] jarFiles = dir.listFiles((dir1, name) -> name.endsWith(".jar"));
if (jarFiles == null) {
return;
}
for (File jarFile : jarFiles) {
loadPlugin(jarFile);
}
}
private void loadPlugin(File jarFile) throws Exception {
// 创建URL类加载器
URL[] urls = new URL[]{jarFile.toURI().toURL()};
URLClassLoader classLoader = new URLClassLoader(urls, getClass().getClassLoader());
// 加载插件描述文件
InputStream is = classLoader.getResourceAsStream("plugin.properties");
if (is == null) {
return;
}
Properties properties = new Properties();
properties.load(is);
// 获取主类
String mainClass = properties.getProperty("main.class");
if (mainClass == null) {
return;
}
// 加载并实例化主类
Class<?> clazz = classLoader.loadClass(mainClass);
if (ImageFilter.class.isAssignableFrom(clazz)) {
ImageFilter filter = (ImageFilter) clazz.getDeclaredConstructor().newInstance();
registerFilter(filter);
}
}
}
// 参数化滤镜(桥接模式)
abstract class ParameterizedFilter implements ImageFilter {
protected Map<String, Object> parameters = new HashMap<>();
public void setParameter(String name, Object value) {
parameters.put(name, value);
}
public Object getParameter(String name) {
return parameters.get(name);
}
}
// 具体参数化滤镜:模糊
class BlurFilter extends ParameterizedFilter {
public BlurFilter() {
// 默认参数
parameters.put("radius", 3);
}
@Override
public String getName() {
return "Blur";
}
@Override
public String getDescription() {
return "使图像模糊";
}
@Override
public BufferedImage apply(BufferedImage image) {
int radius = (int) parameters.getOrDefault("radius", 3);
// 模糊实现,使用参数radius
// ...
return blurredImage;
}
}
使用示例:
public class ImageProcessingApp {
private PluginManager pluginManager = new PluginManager();
public void initialize() throws Exception {
// 注册内置滤镜
pluginManager.registerFilter(new GrayscaleFilter());
BlurFilter blurFilter = new BlurFilter();
blurFilter.setParameter("radius", 5);
pluginManager.registerFilter(blurFilter);
// 创建组合滤镜
CompositeFilter vintageFilter = new CompositeFilter("Vintage", "复古风格效果");
vintageFilter.addFilter(new GrayscaleFilter());
// 添加更多滤镜到组合...
pluginManager.registerFilter(vintageFilter);
// 加载外部插件
pluginManager.loadPlugins("./plugins");
}
public BufferedImage processImage(BufferedImage image, String filterName) {
ImageFilter filter = pluginManager.getFilter(filterName);
if (filter != null) {
return filter.apply(image);
}
return image; // 如果滤镜不存在,返回原图
}
public List<String> getAvailableFilters() {
return pluginManager.getAllFilters().stream()
.map(ImageFilter::getName)
.collect(Collectors.toList());
}
}
第三方插件示例:
// 第三方开发的滤镜插件
public class SepiaFilter implements ImageFilter {
@Override
public String getName() {
return "Sepia";
}
@Override
public String getDescription() {
return "应用复古棕褐色调效果";
}
@Override
public BufferedImage apply(BufferedImage image) {
BufferedImage result = new BufferedImage(
image.getWidth(), image.getHeight(), image.getType());
// 应用复古棕褐色调效果的算法
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
int newR = (int)(0.393 * r + 0.769 * g + 0.189 * b);
int newG = (int)(0.349 * r + 0.686 * g + 0.168 * b);
int newB = (int)(0.272 * r + 0.534 * g + 0.131 * b);
newR = Math.min(newR, 255);
newG = Math.min(newG, 255);
newB = Math.min(newB, 255);
int newRgb = (newR << 16) + (newG << 8) + newB;
result.setRGB(x, y, newRgb);
}
}
return result;
}
}
优势分析:
- 模块化:每个滤镜都是独立的模块
- 动态加载:可以在运行时加载新插件
- 可扩展性:第三方开发者可以创建自己的滤镜
- 组合能力:可以组合多个滤镜创建复杂效果
- 参数化:通过桥接模式支持可配置参数
案例六:数据验证框架的灵活扩展
问题背景
假设我们需要开发一个数据验证框架,用于验证表单输入、API请求等。随着业务规则的增加,验证逻辑会变得越来越复杂,且不同场景下的验证规则可能不同。
初始实现(有问题的方案)
public class DataValidator {
public boolean validateUser(User user) {
// 验证用户名
if (user.getUsername() == null || user.getUsername().length() < 3) {
return false;
}
// 验证密码
if (user.getPassword() == null || !isValidPassword(user.getPassword())) {
return false;
}
// 验证邮箱
if (user.getEmail() == null || !isValidEmail(user.getEmail())) {
return false;
}
return true;
}
public boolean validateProduct(Product product) {
// 验证产品名称
if (product.getName() == null || product.getName().isEmpty()) {
return false;
}
// 验证价格
if (product.getPrice() <= 0) {
return false;
}
// 验证库存
if (product.getStock() < 0) {
return false;
}
return true;
}
// 更多验证方法...
private boolean isValidPassword(String password) {
// 密码验证逻辑
return password.length() >= 8 &&
password.matches(".*[A-Z].*") &&
password.matches(".*[a-z].*") &&
password.matches(".*[0-9].*");
}
private boolean isValidEmail(String email) {
// 邮箱验证逻辑
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
}
问题分析:
- 重复代码:验证逻辑分散在多个方法中
- 难以复用:无法在不同场景中复用验证规则
- 扩展困难:添加新的验证规则需要修改现有代码
- 组合问题:难以组合多个验证规则
使用责任链模式和组合模式的解决方案
// 验证结果类
class ValidationResult {
private boolean valid;
private List<String> errors = new ArrayList<>();
public ValidationResult() {
this.valid = true;
}
public void addError(String field, String message) {
errors.add(field + ": " + message);
valid = false;
}
public boolean isValid() {
return valid;
}
public List<String> getErrors() {
return errors;
}
}
// 验证器接口
interface Validator<T> {
ValidationResult validate(T target);
}
// 组合验证器(组合模式)
class CompositeValidator<T> implements Validator<T> {
private List<Validator<T>> validators = new ArrayList<>();
public void addValidator(Validator<T> validator) {
validators.add(validator);
}
@Override
public ValidationResult validate(T target) {
ValidationResult result = new ValidationResult();
for (Validator<T> validator : validators) {
ValidationResult subResult = validator.validate(target);
if (!subResult.isValid()) {
subResult.getErrors().forEach(error -> result.addError("", error));
}
}
return result;
}
}
// 字段验证器
class FieldValidator<T, F> implements Validator<T> {
private String fieldName;
private Function<T, F> fieldExtractor;
private Predicate<F> validationRule;
private String errorMessage;
public FieldValidator(String fieldName, Function<T, F> fieldExtractor,
Predicate<F> validationRule, String errorMessage) {
this.fieldName = fieldName;
this.fieldExtractor = fieldExtractor;
this.validationRule = validationRule;
this.errorMessage = errorMessage;
}
@Override
public ValidationResult validate(T target) {
ValidationResult result = new ValidationResult();
F fieldValue = fieldExtractor.apply(target);
if (!validationRule.test(fieldValue)) {
result.addError(fieldName, errorMessage);
}
return result;
}
}
// 责任链模式的验证器
class ChainedValidator<T> implements Validator<T> {
private Validator<T> nextValidator;
public ChainedValidator<T> setNext(Validator<T> nextValidator) {
this.nextValidator = nextValidator;
return this;
}
@Override
public ValidationResult validate(T target) {
ValidationResult result = new ValidationResult();
// 当前验证器逻辑
// ...
// 如果有下一个验证器,则继续验证
if (nextValidator != null) {
ValidationResult nextResult = nextValidator.validate(target);
if (!nextResult.isValid()) {
nextResult.getErrors().forEach(error -> result.addError("", error));
}
}
return result;
}
}
// 验证器工厂
class ValidatorFactory {
// 创建用户验证器
public static Validator<User> createUserValidator() {
CompositeValidator<User> validator = new CompositeValidator<>();
// 用户名验证
validator.addValidator(new FieldValidator<>(
"username",
User::getUsername,
username -> username != null && username.length() >= 3,
"用户名长度必须至少为3个字符"
));
// 密码验证
validator.addValidator(new FieldValidator<>(
"password",
User::getPassword,
password -> password != null && password.length() >= 8 &&
password.matches(".*[A-Z].*") &&
password.matches(".*[a-z].*") &&
password.matches(".*[0-9].*"),
"密码必须至少8个字符,包含大小写字母和数字"
));
// 邮箱验证
validator.addValidator(new FieldValidator<>(
"email",
User::getEmail,
email -> email != null && email.matches("^[A-Za-z0-9+_.-]+@(.+)$"),
"邮箱格式不正确"
));
return validator;
}
// 创建产品验证器
public static Validator<Product> createProductValidator() {
CompositeValidator<Product> validator = new CompositeValidator<>();
// 产品名称验证
validator.addValidator(new FieldValidator<>(
"name",
Product::getName,
name -> name != null && !name.isEmpty(),
"产品名称不能为空"
));
// 价格验证
validator.addValidator(new FieldValidator<>(
"price",
Product::getPrice,
price -> price > 0,
"价格必须大于0"
));
// 库存验证
validator.addValidator(new FieldValidator<>(
"stock",
Product::getStock,
stock -> stock >= 0,
"库存不能为负数"
));
return validator;
}
}
使用示例:
public class ValidationDemo {
public static void main(String[] args) {
// 创建验证器
Validator<User> userValidator = ValidatorFactory.createUserValidator();
// 创建用户对象
User user = new User("jo", "password", "invalid-email");
// 验证
ValidationResult result = userValidator.validate(user);
if (!result.isValid()) {
System.out.println("验证失败:");
result.getErrors().forEach(System.out::println);
} else {
System.out.println("验证成功!");
}
// 创建自定义验证器
CompositeValidator<User> customValidator = new CompositeValidator<>();
// 只验证用户名和邮箱
customValidator.addValidator(new FieldValidator<>(
"username",
User::getUsername,
username -> username != null && username.length() >= 2, // 宽松的规则
"用户名长度必须至少为2个字符"
));
customValidator.addValidator(new FieldValidator<>(
"email",
User::getEmail,
email -> email != null && email.contains("@"),
"邮箱必须包含@符号"
));
// 使用自定义验证器
ValidationResult customResult = customValidator.validate(user);
System.out.println("\n自定义验证结果:");
if (!customResult.isValid()) {
customResult.getErrors().forEach(System.out::println);
} else {
System.out.println("验证成功!");
}
}
}
优势分析:
- 灵活组合:可以灵活组合不同的验证规则
- 规则重用:验证规则可以在不同场景中重用
- 扩展简单:添加新规则只需创建新的验证器
- 自定义验证:可以根据需要创建自定义验证逻辑
- 责任分离:每个验证器只负责特定的验证逻辑
总结:设计模式如何提升软件灵活性
通过以上六个实际案例,我们可以看到设计模式在提升软件灵活性方面的巨大优势:
1. 隔离变化点
设计模式帮助我们识别系统中的变化点,并将其封装在特定的模块中。例如:
- 策略模式隔离了算法的变化(支付处理案例)
- 适配器模式隔离了接口不兼容的变化(配置项案例)
- 装饰器模式隔离了功能扩展的变化(报表导出案例)
2. 松耦合设计
设计模式促进组件间的松耦合,降低了依赖性:
- 观察者模式实现了发布者和订阅者的解耦(通知系统案例)
- 桥接模式分离了抽象和实现(插件系统案例)
- 责任链模式解耦了请求发送者和处理者(数据验证案例)
3. 开闭原则实践
设计模式使代码符合开闭原则,对扩展开放,对修改关闭:
- 工厂模式允许添加新的产品而不修改现有代码(支付系统案例)
- 命令模式允许添加新的命令而不修改调用者(报表导出案例)
- 组合模式允许构建复杂的树形结构(数据验证案例)
4. 运行时的灵活性
设计模式提供了运行时调整行为的能力:
- 动态加载插件(插件系统案例)
- 运行时配置更新(配置项案例)
- 动态组合功能(报表导出案例)
5. 应用设计模式的最佳实践
- 识别变化点:首先分析系统中最可能变化的部分
- 选择合适的模式:根据具体问题特征选择适当的设计模式
- 组合使用:复杂问题通常需要多种设计模式协同工作
- 避免过度设计:只在确实需要灵活性的地方应用设计模式
- 持续重构:随着需求变化,不断改进设计
结论
设计模式是解决灵活性问题的强大工具,但不是万能药。合理应用设计模式需要深入理解问题本质,识别变化点,并选择恰当的解决方案。通过本文的六个真实案例,我们看到了设计模式如何在实际项目中提升软件灵活性,使系统更易于维护、扩展和适应变化。
记住,设计模式的价值不在于模式本身,而在于它们所体现的设计原则和解决问题的思路。掌握这些原则和思路,将帮助你设计出更加灵活、健壮的软件系统。