云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

SpringBoot中六种设计模式应用案例二

jxf315 2025-05-27 15:21:57 教程文章 6 ℃

前言:

接着上篇的文档来写继续写设计模式。

8.观察者模式

观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。SpringBoot中的事件机制是观察者模式的典型应用,如ApplicationEvent和ApplicationListener。

// 自定义事件
public class UserRegisteredEvent extends ApplicationEvent {
    
    private final User user;
    
    public UserRegisteredEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
    
    public User getUser() {
        return user;
    }
}

// 事件发布者
@Service
public class UserRegistrationService {
    
    private final ApplicationEventPublisher eventPublisher;
    private final UserRepository userRepository;
    
    @Autowired
    public UserRegistrationService(
            ApplicationEventPublisher eventPublisher,
            UserRepository userRepository) {
        this.eventPublisher = eventPublisher;
        this.userRepository = userRepository;
    }
    
    @Transactional
    public User registerUser(UserRegistrationDto registrationDto) {
        // 创建并保存用户
        User user = new User();
        user.setUsername(registrationDto.getUsername());
        user.setEmail(registrationDto.getEmail());
        user.setPassword(encodePassword(registrationDto.getPassword()));
        user.setRegistrationDate(LocalDateTime.now());
        
        User savedUser = userRepository.save(user);
        
        // 发布用户注册事件
        eventPublisher.publishEvent(new UserRegisteredEvent(this, savedUser));
        
        return savedUser;
    }
    
    private String encodePassword(String password) {
        // 密码加密逻辑
        return "{bcrypt}" + password;
    }
}

// 事件监听器 - 发送欢迎邮件
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {
    
    private final EmailService emailService;
    
    @Autowired
    public WelcomeEmailListener(EmailService emailService) {
        this.emailService = emailService;
    }
    
    @Override
    public void onApplicationEvent(UserRegisteredEvent event) {
        User user = event.getUser();
        
        // 发送欢迎邮件
        emailService.sendWelcomeEmail(user);
    }
}

// 事件监听器 - 创建用户资料
@Component
public class UserProfileInitializer implements ApplicationListener<UserRegisteredEvent> {
    
    private final ProfileService profileService;
    
    @Autowired
    public UserProfileInitializer(ProfileService profileService) {
        this.profileService = profileService;
    }
    
    @Override
    public void onApplicationEvent(UserRegisteredEvent event) {
        User user = event.getUser();
        
        // 创建用户资料
        profileService.createInitialProfile(user);
    }
}

// 使用注解方式的事件监听器
@Component
public class MarketingSubscriptionHandler {
    
    private final MarketingService marketingService;
    
    @Autowired
    public MarketingSubscriptionHandler(MarketingService marketingService) {
        this.marketingService = marketingService;
    }
    
    @EventListener
    @Async
    public void handleUserRegistered(UserRegisteredEvent event) {
        User user = event.getUser();
        
        // 添加到营销列表
        marketingService.addUserToDefaultNewsletters(user);
    }
}

// 异步事件配置
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("EventHandler-");
        executor.initialize();
        return executor;
    }
}

优点

  • 松耦合,事件发布者无需知道谁在监听
  • 支持一对多通知
  • 可实现异步处理和事件分发
  • 便于扩展新的监听者

9. 策略模式

策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换,让算法的变化独立于使用它的客户。策略模式广泛用于SpringBoot中的各种可配置策略,如缓存策略、认证策略等。

// 折扣策略接口
public interface DiscountStrategy {
    BigDecimal applyDiscount(BigDecimal amount, User user);
    boolean isApplicable(User user, ShoppingCart cart);
}

// 新用户折扣策略
@Component
public class NewUserDiscountStrategy implements DiscountStrategy {
    
    @Value("${discount.new-user.percentage:10}")
    private int discountPercentage;
    
    @Override
    public BigDecimal applyDiscount(BigDecimal amount, User user) {
        BigDecimal discountFactor = BigDecimal.valueOf(discountPercentage)
                .divide(BigDecimal.valueOf(100));
        BigDecimal discount = amount.multiply(discountFactor);
        return amount.subtract(discount);
    }
    
    @Override
    public boolean isApplicable(User user, ShoppingCart cart) {
        LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30);
        return user.getRegistrationDate().isAfter(thirtyDaysAgo);
    }
}

// 会员折扣策略
@Component
public class PremiumMemberDiscountStrategy implements DiscountStrategy {
    
    @Value("${discount.premium-member.percentage:15}")
    private int discountPercentage;
    
    @Override
    public BigDecimal applyDiscount(BigDecimal amount, User user) {
        BigDecimal discountFactor = BigDecimal.valueOf(discountPercentage)
                .divide(BigDecimal.valueOf(100));
        BigDecimal discount = amount.multiply(discountFactor);
        return amount.subtract(discount);
    }
    
    @Override
    public boolean isApplicable(User user, ShoppingCart cart) {
        return "PREMIUM".equals(user.getMembershipLevel());
    }
}

// 大订单折扣策略
@Component
public class LargeOrderDiscountStrategy implements DiscountStrategy {
    
    @Value("${discount.large-order.threshold:1000}")
    private BigDecimal threshold;
    
    @Value("${discount.large-order.percentage:5}")
    private int discountPercentage;
    
    @Override
    public BigDecimal applyDiscount(BigDecimal amount, User user) {
        BigDecimal discountFactor = BigDecimal.valueOf(discountPercentage)
                .divide(BigDecimal.valueOf(100));
        BigDecimal discount = amount.multiply(discountFactor);
        return amount.subtract(discount);
    }
    
    @Override
    public boolean isApplicable(User user, ShoppingCart cart) {
        return cart.getTotalAmount().compareTo(threshold) >= 0;
    }
}

// 策略上下文
@Service
public class DiscountService {
    
    private final List<DiscountStrategy> discountStrategies;
    
    @Autowired
    public DiscountService(List<DiscountStrategy> discountStrategies) {
        this.discountStrategies = discountStrategies;
    }
    
    public BigDecimal calculateDiscountedAmount(BigDecimal originalAmount, User user, ShoppingCart cart) {
        // 查找最佳折扣策略
        DiscountStrategy bestStrategy = findBestDiscountStrategy(user, cart);
        
        if (bestStrategy != null) {
            return bestStrategy.applyDiscount(originalAmount, user);
        }
        
        // 无可用折扣
        return originalAmount;
    }
    
    private DiscountStrategy findBestDiscountStrategy(User user, ShoppingCart cart) {
        BigDecimal originalAmount = cart.getTotalAmount();
        BigDecimal bestDiscount = BigDecimal.ZERO;
        DiscountStrategy bestStrategy = null;
        
        for (DiscountStrategy strategy : discountStrategies) {
            if (strategy.isApplicable(user, cart)) {
                BigDecimal discountedAmount = strategy.applyDiscount(originalAmount, user);
                BigDecimal discount = originalAmount.subtract(discountedAmount);
                
                if (discount.compareTo(bestDiscount) > 0) {
                    bestDiscount = discount;
                    bestStrategy = strategy;
                }
            }
        }
        
        return bestStrategy;
    }
}


优点

  • 算法可以独立于使用它的客户而变化
  • 消除条件判断语句
  • 易于扩展新的策略
  • 提高代码复用性

10. 模板方法模式

模板方法模式定义了一个算法的骨架,将一些步骤延迟到子类中实现,使子类可以不改变算法结构的情况下重定义算法的某些步骤。SpringBoot中的JdbcTemplate、RestTemplate等都是模板方法模式的应用。

// 抽象导出处理器
@Component
public abstract class AbstractReportExporter {
    
    // 模板方法定义了算法的骨架
    public final void exportReport(ReportRequest request, OutputStream output) {
        try {
            // 1. 验证请求
            validateRequest(request);
            
            // 2. 获取数据
            ReportData data = fetchData(request);
            
            // 3. 处理数据
            ReportData processedData = processData(data);
            
            // 4. 格式化数据(由子类实现)
            byte[] formattedData = formatData(processedData);
            
            // 5. 写入输出流
            output.write(formattedData);
            output.flush();
            
            // 6. 记录导出操作
            logExport(request, processedData);
            
        } catch (Exception e) {
            handleExportError(e, request);
        }
    }
    
    // 默认实现的方法
    protected void validateRequest(ReportRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("Report request cannot be null");
        }
        
        if (request.getStartDate() == null || request.getEndDate() == null) {
            throw new IllegalArgumentException("Start date and end date are required");
        }
        
        if (request.getStartDate().isAfter(request.getEndDate())) {
            throw new IllegalArgumentException("Start date cannot be after end date");
        }
    }
    
    // 抽象方法,必须由子类实现
    protected abstract ReportData fetchData(ReportRequest request);
    
    // 钩子方法,子类可以选择性覆盖
    protected ReportData processData(ReportData data) {
        // 默认实现:不做任何处理
        return data;
    }
    
    // 抽象方法,必须由子类实现
    protected abstract byte[] formatData(ReportData data) throws IOException;
    
    // 默认实现的方法
    protected void logExport(ReportRequest request, ReportData data) {
        System.out.println("Report exported for period: " + 
                request.getStartDate() + " to " + request.getEndDate() + 
                ", records: " + data.getRecords().size());
    }
    
    // 默认实现的方法
    protected void handleExportError(Exception e, ReportRequest request) {
        System.err.println("Error exporting report: " + e.getMessage());
        throw new ReportExportException("Failed to export report", e);
    }
}

// PDF导出器实现
@Component("pdfExporter")
public class PdfReportExporter extends AbstractReportExporter {
    
    @Autowired
    private ReportRepository reportRepository;
    
    @Override
    protected ReportData fetchData(ReportRequest request) {
        // 从数据库获取报表数据
        List<ReportRecord> records = reportRepository.findByDateRange(
                request.getStartDate(), request.getEndDate());
        
        return new ReportData(records, request.getStartDate(), request.getEndDate());
    }
    
    @Override
    protected ReportData processData(ReportData data) {
        // 处理数据,如排序、分组、计算统计值等
        List<ReportRecord> processedRecords = data.getRecords().stream()
                .sorted(Comparator.comparing(ReportRecord::getDate))
                .collect(Collectors.toList());
        
        return new ReportData(processedRecords, data.getStartDate(), data.getEndDate());
    }
    
    @Override
    protected byte[] formatData(ReportData data) throws IOException {
        Document document = new Document();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
        try {
            PdfWriter.getInstance(document, baos);
            document.open();
            
            // 添加标题
            document.add(new Paragraph("Report from " + 
                    data.getStartDate() + " to " + data.getEndDate()));
            
            // 创建表格
            PdfPTable table = new PdfPTable(3);
            table.addCell("Date");
            table.addCell("Description");
            table.addCell("Amount");
            
            // 添加数据行
            for (ReportRecord record : data.getRecords()) {
                table.addCell(record.getDate().toString());
                table.addCell(record.getDescription());
                table.addCell(record.getAmount().toString());
            }
            
            document.add(table);
            
        } finally {
            if (document.isOpen()) {
                document.close();
            }
        }
        
        return baos.toByteArray();
    }
}

// Excel导出器实现
@Component("excelExporter")
public class ExcelReportExporter extends AbstractReportExporter {
    
    @Autowired
    private ReportRepository reportRepository;
    
    @Override
    protected ReportData fetchData(ReportRequest request) {
        // 从数据库获取报表数据
        List<ReportRecord> records = reportRepository.findByDateRange(
                request.getStartDate(), request.getEndDate());
        
        return new ReportData(records, request.getStartDate(), request.getEndDate());
    }
    
    @Override
    protected byte[] formatData(ReportData data) throws IOException {
        Workbook workbook = new XSSFWorkbook();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
        try {
            Sheet sheet = workbook.createSheet("Report");
            
            // 创建标题行
            Row headerRow = sheet.createRow(0);
            headerRow.createCell(0).setCellValue("Date");
            headerRow.createCell(1).setCellValue("Description");
            headerRow.createCell(2).setCellValue("Amount");
            
            // 添加数据行
            int rowNum = 1;
            for (ReportRecord record : data.getRecords()) {
                Row row = sheet.createRow(rowNum++);
                row.createCell(0).setCellValue(record.getDate().toString());
                row.createCell(1).setCellValue(record.getDescription());
                row.createCell(2).setCellValue(record.getAmount().doubleValue());
            }
            
            // 调整列宽
            for (int i = 0; i < 3; i++) {
                sheet.autoSizeColumn(i);
            }
            
            workbook.write(baos);
            
        } finally {
            workbook.close();
        }
        
        return baos.toByteArray();
    }
}

// 使用模板方法模式
@RestController
@RequestMapping("/reports")
public class ReportController {
    
    @Autowired
    @Qualifier("pdfExporter")
    private AbstractReportExporter pdfExporter;
    
    @Autowired
    @Qualifier("excelExporter")
    private AbstractReportExporter excelExporter;
    
    @GetMapping(value = "/export/pdf", produces = MediaType.APPLICATION_PDF_VALUE)
    public void exportPdf(
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
            HttpServletResponse response) throws IOException {
        
        response.setHeader("Content-Disposition", "attachment; filename=report.pdf");
        
        ReportRequest request = new ReportRequest();
        request.setStartDate(startDate);
        request.setEndDate(endDate);
        
        pdfExporter.exportReport(request, response.getOutputStream());
    }
    
    @GetMapping(value = "/export/excel", 
            produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    public void exportExcel(
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
            HttpServletResponse response) throws IOException {
        
        response.setHeader("Content-Disposition", "attachment; filename=report.xlsx");
        
        ReportRequest request = new ReportRequest();
        request.setStartDate(startDate);
        request.setEndDate(endDate);
        
        excelExporter.exportReport(request, response.getOutputStream());
    }
}

优点

  • 封装不变部分,扩展可变部分
  • 提取公共代码,减少重复
  • 控制子类扩展点
  • 遵循好莱坞原则:"别调用我们,我们会调用你"

11. 责任链模式

责任链模式为请求创建了一个接收者对象的链,请求会沿着这条链传递,直到有一个对象处理它为止。SpringBoot中的Filter链就是责任链模式的应用,多个Filter依次处理请求。

// 抽象处理器
public abstract class PaymentHandler {
    
    protected PaymentHandler nextHandler;
    
    public void setNext(PaymentHandler handler) {
        this.nextHandler = handler;
    }
    
    public abstract PaymentResponse handle(PaymentRequest request);
}

// 验证处理器
@Component
public class ValidationHandler extends PaymentHandler {
    
    @Override
    public PaymentResponse handle(PaymentRequest request) {
        // 验证支付请求
        if (request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return new PaymentResponse(false, "Payment amount must be greater than zero");
        }
        
        if (request.getCardNumber() == null || request.getCardNumber().isEmpty()) {
            return new PaymentResponse(false, "Card number is required");
        }
        
        if (request.getCardNumber().length() < 13 || request.getCardNumber().length() > 19) {
            return new PaymentResponse(false, "Invalid card number length");
        }
        
        if (request.getExpiryDate() == null) {
            return new PaymentResponse(false, "Expiry date is required");
        }
        
        if (request.getExpiryDate().isBefore(YearMonth.now())) {
            return new PaymentResponse(false, "Card has expired");
        }
        
        // 验证通过,继续下一个处理器
        if (nextHandler != null) {
            return nextHandler.handle(request);
        }
        
        return new PaymentResponse(true, "Validation successful");
    }
}

// 欺诈检测处理器
@Component
public class FraudDetectionHandler extends PaymentHandler {
    
    @Autowired
    private FraudDetectionService fraudService;
    
    @Override
    public PaymentResponse handle(PaymentRequest request) {
        // 检查是否存在欺诈风险
        FraudCheckResult checkResult = fraudService.checkForFraud(
                request.getCardNumber(), 
                request.getAmount(),
                request.getIpAddress());
        
        if (checkResult.isFraudulent()) {
            return new PaymentResponse(false, "Transaction flagged as potentially fraudulent: " + 
                    checkResult.getReason());
        }
        
        // 欺诈检查通过,继续下一个处理器
        if (nextHandler != null) {
            return nextHandler.handle(request);
        }
        
        return new PaymentResponse(true, "Fraud check passed");
    }
}

// 支付处理器
@Component
public class PaymentProcessingHandler extends PaymentHandler {
    
    @Autowired
    private PaymentGateway paymentGateway;
    
    @Override
    public PaymentResponse handle(PaymentRequest request) {
        // 实际执行支付
        PaymentGatewayResponse gatewayResponse = paymentGateway.processPayment(
                request.getCardNumber(),
                request.getExpiryDate(),
                request.getCvv(),
                request.getAmount());
        
        if (!gatewayResponse.isSuccessful()) {
            return new PaymentResponse(false, "Payment failed: " + gatewayResponse.getMessage());
        }
        
        // 支付成功,继续下一个处理器
        if (nextHandler != null) {
            PaymentResponse nextResponse = nextHandler.handle(request);
            
            // 如果下一环节失败,需要进行退款
            if (!nextResponse.isSuccess()) {
                paymentGateway.refund(gatewayResponse.getTransactionId(), request.getAmount());
                return nextResponse;
            }
            
            // 添加交易ID到响应
            nextResponse.setTransactionId(gatewayResponse.getTransactionId());
            return nextResponse;
        }
        
        return new PaymentResponse(true, "Payment processed successfully", 
                gatewayResponse.getTransactionId());
    }
}

// 通知处理器
@Component
public class NotificationHandler extends PaymentHandler {
    
    @Autowired
    private NotificationService notificationService;
    
    @Override
    public PaymentResponse handle(PaymentRequest request) {
        // 发送支付成功通知
        notificationService.sendPaymentConfirmation(
                request.getEmail(),
                request.getAmount(),
                LocalDateTime.now());
        
        // 继续下一个处理器
        if (nextHandler != null) {
            return nextHandler.handle(request);
        }
        
        return new PaymentResponse(true, "Payment completed and notification sent");
    }
}

// 责任链配置
@Configuration
public class PaymentHandlerConfig {
    
    @Bean
    public PaymentHandler paymentHandlerChain(
            ValidationHandler validationHandler,
            FraudDetectionHandler fraudDetectionHandler,
            PaymentProcessingHandler paymentProcessingHandler,
            NotificationHandler notificationHandler) {
        
        // 构建处理链
        validationHandler.setNext(fraudDetectionHandler);
        fraudDetectionHandler.setNext(paymentProcessingHandler);
        paymentProcessingHandler.setNext(notificationHandler);
        
        // 返回链的第一个处理器
        return validationHandler;
    }
}

// 支付服务
@Service
public class PaymentService {
    
    private final PaymentHandler paymentHandlerChain;
    
    @Autowired
    public PaymentService(PaymentHandler paymentHandlerChain) {
        this.paymentHandlerChain = paymentHandlerChain;
    }
    
    public PaymentResponse processPayment(PaymentRequest request) {
        // 启动责任链处理
        return paymentHandlerChain.handle(request);
    }
}

优点

  • 降低耦合度,请求发送者和接收者解耦
  • 动态组合处理器,灵活调整处理流程
  • 符合单一职责原则,每个处理器专注于一项任务
  • 易于添加新的处理器,扩展性好

12. 命令模式

命令模式将请求封装成对象,使发出请求的责任和执行请求的责任分割开,支持请求排队、回退等功能。在SpringBoot应用的事件处理、任务调度中经常使用命令模式。

// 命令接口
public interface Command {
    void execute();
    void undo();
    String getDescription();
}

// 具体命令 - 创建订单
@Component
public class CreateOrderCommand implements Command {
    
    private final OrderService orderService;
    private final OrderRepository orderRepository;
    
    private Order createdOrder;
    private final Order orderToCreate;
    
    public CreateOrderCommand(
            OrderService orderService,
            OrderRepository orderRepository,
            Order orderToCreate) {
        this.orderService = orderService;
        this.orderRepository = orderRepository;
        this.orderToCreate = orderToCreate;
    }
    
    @Override
    public void execute() {
        createdOrder = orderService.createOrder(orderToCreate);
    }
    
    @Override
    public void undo() {
        if (createdOrder != null) {
            orderRepository.delete(createdOrder);
            createdOrder = null;
        }
    }
    
    @Override
    public String getDescription() {
        return "Create order for customer: " + orderToCreate.getCustomerId();
    }
}

// 具体命令 - 扣减库存
@Component
public class DeductInventoryCommand implements Command {
    
    private final InventoryService inventoryService;
    
    private final Long productId;
    private final int quantity;
    private boolean executed = false;
    
    public DeductInventoryCommand(
            InventoryService inventoryService,
            Long productId,
            int quantity) {
        this.inventoryService = inventoryService;
        this.productId = productId;
        this.quantity = quantity;
    }
    
    @Override
    public void execute() {
        inventoryService.deductStock(productId, quantity);
        executed = true;
    }
    
    @Override
    public void undo() {
        if (executed) {
            inventoryService.addStock(productId, quantity);
            executed = false;
        }
    }
    
    @Override
    public String getDescription() {
        return "Deduct " + quantity + " units from product: " + productId;
    }
}

// 具体命令 - 处理支付
@Component
public class ProcessPaymentCommand implements Command {
    
    private final PaymentService paymentService;
    
    private final PaymentRequest paymentRequest;
    private String transactionId;
    
    public ProcessPaymentCommand(
            PaymentService paymentService,
            PaymentRequest paymentRequest) {
        this.paymentService = paymentService;
        this.paymentRequest = paymentRequest;
    }
    
    @Override
    public void execute() {
        PaymentResponse response = paymentService.processPayment(paymentRequest);
        
        if (!response.isSuccess()) {
            throw new PaymentFailedException(response.getMessage());
        }
        
        this.transactionId = response.getTransactionId();
    }
    
    @Override
    public void undo() {
        if (transactionId != null) {
            paymentService.refundPayment(transactionId);
            transactionId = null;
        }
    }
    
    @Override
    public String getDescription() {
        return "Process payment of " + paymentRequest.getAmount() + 
                " for order: " + paymentRequest.getOrderId();
    }
}

// 命令历史记录
@Component
public class CommandHistory {
    
    private final Deque<Command> history = new ArrayDeque<>();
    
    public void push(Command command) {
        history.push(command);
    }
    
    public Command pop() {
        return history.isEmpty() ? null : history.pop();
    }
    
    public boolean isEmpty() {
        return history.isEmpty();
    }
    
    public List<Command> getExecutedCommands() {
        return new ArrayList<>(history);
    }
}

// 命令执行器
@Service
public class CommandInvoker {
    
    private final CommandHistory history;
    private final TransactionTemplate transactionTemplate;
    
    @Autowired
    public CommandInvoker(
            CommandHistory history,
            PlatformTransactionManager transactionManager) {
        this.history = history;
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }
    
    public void executeCommand(Command command) {
        transactionTemplate.execute(status -> {
            try {
                command.execute();
                history.push(command);
                return null;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
    }
    
    public void executeCommands(List<Command> commands) {
        transactionTemplate.execute(status -> {
            List<Command> executedCommands = new ArrayList<>();
            
            try {
                for (Command command : commands) {
                    command.execute();
                    executedCommands.add(command);
                }
                
                // 所有命令执行成功后添加到历史记录
                for (Command command : executedCommands) {
                    history.push(command);
                }
                
                return null;
            } catch (Exception e) {
                // 出现异常,回滚已执行的命令
                for (int i = executedCommands.size() - 1; i >= 0; i--) {
                    executedCommands.get(i).undo();
                }
                
                status.setRollbackOnly();
                throw e;
            }
        });
    }
    
    public void undoLastCommand() {
        Command command = history.pop();
        
        if (command != null) {
            transactionTemplate.execute(status -> {
                try {
                    command.undo();
                    return null;
                } catch (Exception e) {
                    status.setRollbackOnly();
                    // 撤销失败,将命令重新放回历史
                    history.push(command);
                    throw e;
                }
            });
        }
    }
}

// 订单处理服务
@Service
public class OrderProcessingService {
    
    private final CommandInvoker commandInvoker;
    private final OrderService orderService;
    private final InventoryService inventoryService;
    private final PaymentService paymentService;
    
    @Autowired
    public OrderProcessingService(
            CommandInvoker commandInvoker,
            OrderService orderService,
            InventoryService inventoryService,
            PaymentService paymentService) {
        this.commandInvoker = commandInvoker;
        this.orderService = orderService;
        this.inventoryService = inventoryService;
        this.paymentService = paymentService;
    }
    
    public Order placeOrder(OrderRequest orderRequest) {
        // 准备订单数据
        Order order = new Order();
        order.setCustomerId(orderRequest.getCustomerId());
        order.setItems(orderRequest.getItems());
        order.setTotalAmount(calculateTotal(orderRequest.getItems()));
        
        // 创建支付请求
        PaymentRequest paymentRequest = new PaymentRequest();
        paymentRequest.setAmount(order.getTotalAmount());
        paymentRequest.setCardNumber(orderRequest.getPaymentDetails().getCardNumber());
        paymentRequest.setExpiryDate(orderRequest.getPaymentDetails().getExpiryDate());
        paymentRequest.setCvv(orderRequest.getPaymentDetails().getCvv());
        
        // 创建命令列表
        List<Command> commands = new ArrayList<>();
        
        // 1. 创建订单命令
        Command createOrderCommand = new CreateOrderCommand(orderService, orderService.getRepository(), order);
        commands.add(createOrderCommand);
        
        // 2. 扣减库存命令
        for (OrderItem item : order.getItems()) {
            Command deductInventoryCommand = new DeductInventoryCommand(
                    inventoryService, 
                    item.getProductId(), 
                    item.getQuantity());
            commands.add(deductInventoryCommand);
        }
        
        // 3. 处理支付命令
        Command processPaymentCommand = new ProcessPaymentCommand(paymentService, paymentRequest);
        commands.add(processPaymentCommand);
        
        // 执行命令序列
        commandInvoker.executeCommands(commands);
        
        return order;
    }
    
    private BigDecimal calculateTotal(List<OrderItem> items) {
        return items.stream()
                .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

优点

  • 请求发送者和接收者解耦
  • 支持撤销操作
  • 可以组合命令实现复杂操作
  • 便于实现事务和日志

13. 状态模式

状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

在业务流程处理、订单状态管理等场景常用状态模式。

// 订单状态接口
public interface OrderState {
    OrderState confirm(Order order);
    OrderState pay(Order order);
    OrderState ship(Order order);
    OrderState deliver(Order order);
    OrderState cancel(Order order);
    OrderState refund(Order order);
    String getStatus();
}

// 具体状态 - 新建
@Component
public class NewOrderState implements OrderState {
    
    @Autowired
    private ConfirmedOrderState confirmedOrderState;
    
    @Autowired
    private CancelledOrderState cancelledOrderState;
    
    @Override
    public OrderState confirm(Order order) {
        // 执行确认逻辑
        order.setConfirmedAt(LocalDateTime.now());
        return confirmedOrderState;
    }
    
    @Override
    public OrderState pay(Order order) {
        throw new IllegalStateException("Cannot pay for an order that has not been confirmed");
    }
    
    @Override
    public OrderState ship(Order order) {
        throw new IllegalStateException("Cannot ship an order that has not been confirmed and paid");
    }
    
    @Override
    public OrderState deliver(Order order) {
        throw new IllegalStateException("Cannot deliver an order that has not been shipped");
    }
    
    @Override
    public OrderState cancel(Order order) {
        // 执行取消逻辑
        order.setCancelledAt(LocalDateTime.now());
        order.setCancellationReason("Cancelled by customer before confirmation");
        return cancelledOrderState;
    }
    
    @Override
    public OrderState refund(Order order) {
        throw new IllegalStateException("Cannot refund an order that has not been paid");
    }
    
    @Override
    public String getStatus() {
        return "NEW";
    }
}

// 具体状态 - 已确认
@Component
public class ConfirmedOrderState implements OrderState {
    
    @Autowired
    private PaidOrderState paidOrderState;
    
    @Autowired
    private CancelledOrderState cancelledOrderState;
    
    @Override
    public OrderState confirm(Order order) {
        throw new IllegalStateException("Order is already confirmed");
    }
    
    @Override
    public OrderState pay(Order order) {
        // 执行支付逻辑
        order.setPaidAt(LocalDateTime.now());
        return paidOrderState;
    }
    
    @Override
    public OrderState ship(Order order) {
        throw new IllegalStateException("Cannot ship an order that has not been paid");
    }
    
    @Override
    public OrderState deliver(Order order) {
        throw new IllegalStateException("Cannot deliver an order that has not been shipped");
    }
    
    @Override
    public OrderState cancel(Order order) {
        // 执行取消逻辑
        order.setCancelledAt(LocalDateTime.now());
        order.setCancellationReason("Cancelled by customer after confirmation");
        return cancelledOrderState;
    }
    
    @Override
    public OrderState refund(Order order) {
        throw new IllegalStateException("Cannot refund an order that has not been paid");
    }
    
    @Override
    public String getStatus() {
        return "CONFIRMED";
    }
}

// 具体状态 - 已支付
@Component
public class PaidOrderState implements OrderState {
    
    @Autowired
    private ShippedOrderState shippedOrderState;
    
    @Autowired
    private RefundedOrderState refundedOrderState;
    
    @Override
    public OrderState confirm(Order order) {
        throw new IllegalStateException("Order is already confirmed");
    }
    
    @Override
    public OrderState pay(Order order) {
        throw new IllegalStateException("Order is already paid");
    }
    
    @Override
    public OrderState ship(Order order) {
        // 执行发货逻辑
        order.setShippedAt(LocalDateTime.now());
        return shippedOrderState;
    }
    
    @Override
    public OrderState deliver(Order order) {
        throw new IllegalStateException("Cannot deliver an order that has not been shipped");
    }
    
    @Override
    public OrderState cancel(Order order) {
        throw new IllegalStateException("Cannot cancel an order that has been paid, please request a refund");
    }
    
    @Override
    public OrderState refund(Order order) {
        // 执行退款逻辑
        order.setRefundedAt(LocalDateTime.now());
        return refundedOrderState;
    }
    
    @Override
    public String getStatus() {
        return "PAID";
    }
}

// 更多状态类实现...

// 订单状态上下文类
@Entity
@Table(name = "orders")
@Data
public class Order {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private Long customerId;
    
    @OneToMany(cascade = CascadeType.ALL)
    private List<OrderItem> items;
    
    private BigDecimal totalAmount;
    
    private LocalDateTime createdAt = LocalDateTime.now();
    
    private LocalDateTime confirmedAt;
    
    private LocalDateTime paidAt;
    
    private LocalDateTime shippedAt;
    
    private LocalDateTime deliveredAt;
    
    private LocalDateTime cancelledAt;
    
    private String cancellationReason;
    
    private LocalDateTime refundedAt;
    
    @Transient
    private OrderState currentState;
    
    @Column(name = "status")
    private String status = "NEW";
    
    @PostLoad
    private void onLoad() {
        initState();
    }
    
    private void initState() {
        if (status == null) {
            status = "NEW";
        }
        
        switch (status) {
            case "NEW":
                currentState = SpringContextHolder.getBean(NewOrderState.class);
                break;
            case "CONFIRMED":
                currentState = SpringContextHolder.getBean(ConfirmedOrderState.class);
                break;
            case "PAID":
                currentState = SpringContextHolder.getBean(PaidOrderState.class);
                break;
            case "SHIPPED":
                currentState = SpringContextHolder.getBean(ShippedOrderState.class);
                break;
            case "DELIVERED":
                currentState = SpringContextHolder.getBean(DeliveredOrderState.class);
                break;
            case "CANCELLED":
                currentState = SpringContextHolder.getBean(CancelledOrderState.class);
                break;
            case "REFUNDED":
                currentState = SpringContextHolder.getBean(RefundedOrderState.class);
                break;
            default:
                throw new IllegalStateException("Unknown order status: " + status);
        }
    }
    
    // 状态转换方法
    public void confirm() {
        currentState = currentState.confirm(this);
        status = currentState.getStatus();
    }
    
    public void pay() {
        currentState = currentState.pay(this);
        status = currentState.getStatus();
    }
    
    public void ship() {
        currentState = currentState.ship(this);
        status = currentState.getStatus();
    }
    
    public void deliver() {
        currentState = currentState.deliver(this);
        status = currentState.getStatus();
    }
    
    public void cancel() {
        currentState = currentState.cancel(this);
        status = currentState.getStatus();
    }
    
    public void refund() {
        currentState = currentState.refund(this);
        status = currentState.getStatus();
    }
}

// 订单服务
@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private NewOrderState initialState;
    
    @Transactional
    public Order createOrder(Long customerId, List<OrderItem> items, BigDecimal totalAmount) {
        Order order = new Order();
        order.setCustomerId(customerId);
        order.setItems(items);
        order.setTotalAmount(totalAmount);
        order.setCurrentState(initialState);
        
        return orderRepository.save(order);
    }
    
    @Transactional
    public Order confirmOrder(Long orderId) {
        Order order = findOrderById(orderId);
        order.confirm();
        return orderRepository.save(order);
    }
    
    @Transactional
    public Order payOrder(Long orderId) {
        Order order = findOrderById(orderId);
        order.pay();
        return orderRepository.save(order);
    }
    
    @Transactional
    public Order shipOrder(Long orderId) {
        Order order = findOrderById(orderId);
        order.ship();
        return orderRepository.save(order);
    }
    
    @Transactional
    public Order deliverOrder(Long orderId) {
        Order order = findOrderById(orderId);
        order.deliver();
        return orderRepository.save(order);
    }
    
    @Transactional
    public Order cancelOrder(Long orderId) {
        Order order = findOrderById(orderId);
        order.cancel();
        return orderRepository.save(order);
    }
    
    @Transactional
    public Order refundOrder(Long orderId) {
        Order order = findOrderById(orderId);
        order.refund();
        return orderRepository.save(order);
    }
    
    private Order findOrderById(Long orderId) {
        return orderRepository.findById(orderId)
                .orElseThrow(() -> new OrderNotFoundException("Order not found: " + orderId));
    }
}

优点

  • 封装状态相关行为,使代码更加清晰
  • 新增状态只需要添加新类,不需要修改现有代码
  • 消除条件判断语句
  • 显式地表达状态转换规则

总结

设计模式是工具而非目的,应根据实际问题选择合适的模式,避免过度设计。合理运用设计模式,才能真正提升代码质量和开发效率。

最近发表
标签列表