网站首页 > 教程文章 正文
前言:
接着上篇的文档来写继续写设计模式。
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));
}
}
优点
- 封装状态相关行为,使代码更加清晰
- 新增状态只需要添加新类,不需要修改现有代码
- 消除条件判断语句
- 显式地表达状态转换规则
总结
设计模式是工具而非目的,应根据实际问题选择合适的模式,避免过度设计。合理运用设计模式,才能真正提升代码质量和开发效率。
猜你喜欢
- 2025-05-27 还在为 Spring Boot3 整合 Easy Excel 发愁?一文搞定!
- 2025-05-27 7种方式,教你提升 SpringBoot 项目的吞吐量
- 2025-05-27 Tomcat处理HTTP请求流程解析
- 2025-05-27 生产实战:循环继承依赖 导致web 项目启动失败,总是超时
- 2025-05-27 Java Web应用调优线程池:没你想的那么复杂
- 2025-05-27 SpringMVC异常处理句柄这些细节你知道吗?
- 2025-05-27 惊呆了!Controller接口返回值支持17种逆天类型
- 2025-05-27 【干货】EasyExcel确实好用,Springboot+EasyExcel实操
- 2025-05-27 Spring Boot 应用如何防护 XSS 攻击
- 2025-05-27 java验证码生成
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)