在软件开发的世界中,变化是唯一的常量。需求变更、功能扩展、技术迭代不断挑战着我们的代码设计。一个缺乏灵活性的系统往往会在这些变化面前显得脆弱,导致大量的重构工作和潜在的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)) {
                // 更新订单状态
            }
        }
        // 未来添加更多回调处理...
    }
}

问题分析

  1. 违反开闭原则:每次添加新支付方式,都需要修改核心业务逻辑,增加if-else分支
  2. 职责过于集中:一个类负责所有支付方式的处理
  3. 代码膨胀:随着支付方式增加,方法体会变得臃肿难以维护
  4. 测试困难:添加新的支付方式可能影响现有功能

使用策略模式和工厂模式的解决方案

我们可以结合策略模式和工厂模式来重构支付系统:

// 策略接口
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());

优势分析

  1. 开闭原则:添加新支付方式无需修改现有代码,只需创建新的策略类并注册
  2. 单一职责:每个策略类只负责一种支付方式
  3. 代码解耦:支付类型和处理逻辑解耦
  4. 易于测试:可以独立测试每种支付策略
  5. 运行时灵活性:支持动态注册新的支付方式

案例二:通知系统的管理和扩展

问题背景

假设我们正在构建一个电商平台的通知系统,需要在特定事件发生(如订单状态变更、库存预警)时通知相关人员。最初可能只有邮件通知,但随着系统发展,需要增加短信、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());
        }
        // 其他状态处理...
    }
}

问题分析

  1. 强耦合:业务逻辑与通知机制紧密耦合
  2. 难以扩展:增加新的通知方式需要修改业务代码
  3. 重复代码:每个状态变更处重复编写通知逻辑
  4. 不易配置:无法灵活配置特定状态下使用何种通知方式

使用观察者模式的解决方案

// 事件类
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());

优势分析

  1. 松耦合:业务逻辑与通知实现分离
  2. 易于扩展:添加新的通知方式只需创建新的观察者并注册
  3. 集中管理:通知逻辑集中在各自的观察者类中
  4. 运行时配置:可在运行时动态添加或移除通知方式

案例三:报表导出功能的灵活扩展

问题背景

假设我们的系统需要支持多种格式的报表导出功能,如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();
        }
        // 其他格式...
    }
}

问题分析

  1. 代码重复:每种格式的处理逻辑都在同一个方法中
  2. 难以维护:方法体过长,逻辑复杂
  3. 扩展性差:添加新格式需要修改现有代码
  4. 功能限制:难以为不同格式提供自定义选项

使用模板方法模式和装饰器模式的解决方案

首先使用模板方法模式抽象出导出流程:

// 抽象导出器基类
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);
}

优势分析

  1. 代码结构清晰:每种导出格式有自己的实现类
  2. 功能扩展灵活:可以动态组合多种功能(加密、压缩等)
  3. 符合开闭原则:添加新格式或新功能不需要修改现有代码
  4. 复用模板流程:统一的导出流程,减少重复代码

案例四:配置项动态加载与应用

问题背景

假设我们有一个系统需要支持多样化的配置项,这些配置可能来自不同来源(配置文件、数据库、远程服务等),并且需要支持运行时热更新,且不同组件需要响应配置变更。

初始实现(有问题的方案)

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);
        // 重置缓存等操作
    }
}

问题分析

  1. 强耦合:配置类直接引用了具体服务
  2. 难以扩展:添加新的配置源需要修改核心逻辑
  3. 代码重复:每个需要通知的组件都要手动编写通知代码
  4. 可维护性差:配置项增加时需要修改多处代码

使用观察者模式与适配器模式的解决方案

// 配置源接口
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();
    }
}

优势分析

  1. 松耦合:配置管理器不直接依赖具体服务
  2. 可扩展:易于添加新的配置源或监听器
  3. 响应式更新:配置变更自动通知相关组件
  4. 优化性能:通过缓存减少配置查询开销
  5. 集中管理:统一的配置访问接口

案例五:插件系统的动态加载与扩展

问题背景

假设我们正在开发一个图像处理应用,需要支持各种滤镜和效果,这些功能需要以插件形式动态加载,便于第三方开发者扩展。

初始实现(有问题的方案)

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;
    }
    
    // 更多滤镜...
}

问题分析

  1. 代码膨胀:每增加一个滤镜,类就要膨胀
  2. 无法动态加载:新功能需要重新编译和部署整个应用
  3. 无法扩展:第三方无法添加自定义滤镜
  4. 测试困难:每次添加新滤镜都可能影响其他代码

使用组合模式、桥接模式和插件加载器解决方案

// 滤镜接口
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;
    }
}

优势分析

  1. 模块化:每个滤镜都是独立的模块
  2. 动态加载:可以在运行时加载新插件
  3. 可扩展性:第三方开发者可以创建自己的滤镜
  4. 组合能力:可以组合多个滤镜创建复杂效果
  5. 参数化:通过桥接模式支持可配置参数

案例六:数据验证框架的灵活扩展

问题背景

假设我们需要开发一个数据验证框架,用于验证表单输入、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+_.-]+@(.+)$");
    }
}

问题分析

  1. 重复代码:验证逻辑分散在多个方法中
  2. 难以复用:无法在不同场景中复用验证规则
  3. 扩展困难:添加新的验证规则需要修改现有代码
  4. 组合问题:难以组合多个验证规则

使用责任链模式和组合模式的解决方案

// 验证结果类
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. 责任分离:每个验证器只负责特定的验证逻辑

总结:设计模式如何提升软件灵活性

通过以上六个实际案例,我们可以看到设计模式在提升软件灵活性方面的巨大优势:

1. 隔离变化点

设计模式帮助我们识别系统中的变化点,并将其封装在特定的模块中。例如:

  • 策略模式隔离了算法的变化(支付处理案例)
  • 适配器模式隔离了接口不兼容的变化(配置项案例)
  • 装饰器模式隔离了功能扩展的变化(报表导出案例)

2. 松耦合设计

设计模式促进组件间的松耦合,降低了依赖性:

  • 观察者模式实现了发布者和订阅者的解耦(通知系统案例)
  • 桥接模式分离了抽象和实现(插件系统案例)
  • 责任链模式解耦了请求发送者和处理者(数据验证案例)

3. 开闭原则实践

设计模式使代码符合开闭原则,对扩展开放,对修改关闭:

  • 工厂模式允许添加新的产品而不修改现有代码(支付系统案例)
  • 命令模式允许添加新的命令而不修改调用者(报表导出案例)
  • 组合模式允许构建复杂的树形结构(数据验证案例)

4. 运行时的灵活性

设计模式提供了运行时调整行为的能力:

  • 动态加载插件(插件系统案例)
  • 运行时配置更新(配置项案例)
  • 动态组合功能(报表导出案例)

5. 应用设计模式的最佳实践

  1. 识别变化点:首先分析系统中最可能变化的部分
  2. 选择合适的模式:根据具体问题特征选择适当的设计模式
  3. 组合使用:复杂问题通常需要多种设计模式协同工作
  4. 避免过度设计:只在确实需要灵活性的地方应用设计模式
  5. 持续重构:随着需求变化,不断改进设计

结论

设计模式是解决灵活性问题的强大工具,但不是万能药。合理应用设计模式需要深入理解问题本质,识别变化点,并选择恰当的解决方案。通过本文的六个真实案例,我们看到了设计模式如何在实际项目中提升软件灵活性,使系统更易于维护、扩展和适应变化。

记住,设计模式的价值不在于模式本身,而在于它们所体现的设计原则和解决问题的思路。掌握这些原则和思路,将帮助你设计出更加灵活、健壮的软件系统。

Categorized in: