SpringBoot中13种设计模式应用案例
设计模式是软件开发中解决特定问题的经验总结。在SpringBoot框架中,设计模式被巧妙地融入各个环节,不仅提高了框架的灵活性和扩展性,还为开发者提供了优雅的解决方案。本文将介绍13种设计模式在SpringBoot中的实际应用,每个模式都配有具体的代码实现和应用场景。
单例模式 (Singleton Pattern)
模式概述
单例模式确保一个类只有一个实例,并提供一个全局访问点。
SpringBoot应用
SpringBoot中的Bean默认都是单例的,由Spring容器负责创建和管理,保证全局唯一性。
实现示例
@Service
public class UserService {
// 构造方法私有化防止外部直接创建实例
private UserService() {
System.out.println("UserService实例被创建");
}
// Bean的作用域默认为singleton
@Autowired
private UserRepository userRepository;
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
@RestController
public class UserController {
// 注入的是同一个UserService实例
@Autowired
private UserService userService;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
应用优势
- 减少内存占用,避免重复创建对象
- 便于管理共享资源
- 简化对象跟踪和引用
工厂方法模式 (Factory Method Pattern)
模式概述
工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。
SpringBoot应用
SpringBoot中的BeanFactory就是典型的工厂方法模式应用,它负责创建和管理Bean实例。
实现示例
// 支付处理器接口
public interface PaymentProcessor {
void processPayment(double amount);
}
// 具体实现 - 信用卡支付
@Component("creditCard")
public class CreditCardProcessor implements PaymentProcessor {
@Override
public void processPayment(double amount) {
System.out.println("Processing credit card payment of $" + amount);
}
}
// 具体实现 - PayPal支付
@Component("paypal")
public class PayPalProcessor implements PaymentProcessor {
@Override
public void processPayment(double amount) {
System.out.println("Processing PayPal payment of $" + amount);
}
}
// 支付处理器工厂
@Component
public class PaymentProcessorFactory {
@Autowired
private Map<String, PaymentProcessor> processors;
public PaymentProcessor getProcessor(String type) {
PaymentProcessor processor = processors.get(type);
if (processor == null) {
throw new IllegalArgumentException("No payment processor found for type: " + type);
}
return processor;
}
}
// 使用工厂
@Service
public class OrderService {
@Autowired
private PaymentProcessorFactory processorFactory;
public void placeOrder(String paymentType, double amount) {
PaymentProcessor processor = processorFactory.getProcessor(paymentType);
processor.processPayment(amount);
// 处理订单其余部分...
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
应用优势
- 松耦合,客户端与具体实现分离
- 符合开闭原则,可以方便地添加新的支付方式
- 封装对象创建逻辑,统一管理
抽象工厂模式 (Abstract Factory Pattern)
模式概述
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
SpringBoot应用
SpringBoot中的多环境配置和数据源创建就是抽象工厂模式的应用。
实现示例
// 抽象产品 - 连接
public interface Connection {
void connect();
void executeQuery(String query);
void close();
}
// 抽象产品 - 事务
public interface Transaction {
void begin();
void commit();
void rollback();
}
// 抽象工厂
public interface DatabaseFactory {
Connection createConnection();
Transaction createTransaction();
}
// 具体工厂 - MySQL
@Component("mysqlFactory")
@ConditionalOnProperty(name = "db.type", havingValue = "mysql")
public class MySQLDatabaseFactory implements DatabaseFactory {
@Override
public Connection createConnection() {
return new MySQLConnection();
}
@Override
public Transaction createTransaction() {
return new MySQLTransaction();
}
}
// 具体工厂 - PostgreSQL
@Component("postgresFactory")
@ConditionalOnProperty(name = "db.type", havingValue = "postgres")
public class PostgresDatabaseFactory implements DatabaseFactory {
@Override
public Connection createConnection() {
return new PostgresConnection();
}
@Override
public Transaction createTransaction() {
return new PostgresTransaction();
}
}
// 具体产品实现 - MySQL连接
public class MySQLConnection implements Connection {
@Override
public void connect() {
System.out.println("Connecting to MySQL database");
}
@Override
public void executeQuery(String query) {
System.out.println("Executing query on MySQL: " + query);
}
@Override
public void close() {
System.out.println("Closing MySQL connection");
}
}
// 使用抽象工厂
@Service
public class QueryService {
private final DatabaseFactory databaseFactory;
@Autowired
public QueryService(@Qualifier("mysqlFactory") DatabaseFactory databaseFactory) {
this.databaseFactory = databaseFactory;
}
public void executeQuery(String query) {
Connection connection = databaseFactory.createConnection();
Transaction transaction = databaseFactory.createTransaction();
try {
connection.connect();
transaction.begin();
connection.executeQuery(query);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
connection.close();
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
应用优势
- 提供一组相关对象而非单个对象
- 确保创建的产品相互匹配
- 便于环境切换(如开发、测试、生产环境)
建造者模式 (Builder Pattern)
模式概述
建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
SpringBoot应用
SpringBoot中的配置类和链式API设计中大量使用了建造者模式。
实现示例
// 产品类
@Data
public class EmailMessage {
private String from;
private List<String> to;
private List<String> cc;
private String subject;
private String body;
private boolean html;
private List<String> attachments;
private LocalDateTime scheduledTime;
// 私有构造器,只能通过Builder创建
private EmailMessage() {}
// 建造者类
public static class Builder {
private EmailMessage message;
public Builder() {
message = new EmailMessage();
message.to = new ArrayList<>();
message.cc = new ArrayList<>();
message.attachments = new ArrayList<>();
}
public Builder from(String from) {
message.from = from;
return this;
}
public Builder to(String to) {
message.to.add(to);
return this;
}
public Builder cc(String cc) {
message.cc.add(cc);
return this;
}
public Builder subject(String subject) {
message.subject = subject;
return this;
}
public Builder body(String body) {
message.body = body;
return this;
}
public Builder html(boolean html) {
message.html = html;
return this;
}
public Builder attachment(String attachment) {
message.attachments.add(attachment);
return this;
}
public Builder scheduledTime(LocalDateTime scheduledTime) {
message.scheduledTime = scheduledTime;
return this;
}
public EmailMessage build() {
if (message.from == null || message.to.isEmpty() || message.subject == null) {
throw new IllegalStateException("From, To and Subject are required");
}
return message;
}
}
}
// 服务使用建造者模式
@Service
public class EmailService {
// 使用建造者构造复杂对象
public void sendWelcomeEmail(User user) {
EmailMessage message = new EmailMessage.Builder()
.from("noreply@example.com")
.to(user.getEmail())
.subject("Welcome to Our Platform")
.body("<h1>Welcome, " + user.getName() + "!</h1><p>Thanks for joining us.</p>")
.html(true)
.build();
sendEmail(message);
}
private void sendEmail(EmailMessage message) {
// 发送邮件逻辑
System.out.println("Sending email: " + message);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
应用优势
- 参数可控制性强,可以逐步构建对象
- 良好的可读性,类似自然语言描述
- 支持多种配置组合,而不需要大量重载的构造函数
原型模式 (Prototype Pattern)
模式概述
原型模式通过复制现有对象而非创建新实例来创建对象,用于创建成本高昂的对象。
SpringBoot应用
SpringBoot中的bean作用域prototype就是原型模式的应用,每次获取都会创建新的实例。
实现示例
// 支持克隆的配置类
@Component
@Scope("prototype")
public class ReportConfiguration implements Cloneable {
private String reportType;
private List<String> columns;
private String sortBy;
private boolean ascending;
private String dateRange;
// 默认构造器设置基础配置
public ReportConfiguration() {
this.reportType = "summary";
this.columns = new ArrayList<>(Arrays.asList("id", "name", "date"));
this.sortBy = "date";
this.ascending = false;
this.dateRange = "last7days";
}
@Override
public ReportConfiguration clone() {
try {
ReportConfiguration clone = (ReportConfiguration) super.clone();
// 深复制列表
clone.columns = new ArrayList<>(this.columns);
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// getter和setter方法
// ...
}
// 报表工厂使用原型模式
@Service
public class ReportFactory {
// 注入原型bean
@Autowired
private ReportConfiguration defaultConfig;
// 存储预定义的模板
private Map<String, ReportConfiguration> templates = new HashMap<>();
@PostConstruct
public void initTemplates() {
// 创建财务报表模板
ReportConfiguration financialTemplate = defaultConfig.clone();
financialTemplate.setReportType("financial");
financialTemplate.setColumns(Arrays.asList("id", "amount", "transaction_date", "category"));
financialTemplate.setSortBy("amount");
templates.put("financial", financialTemplate);
// 创建用户活动报表模板
ReportConfiguration activityTemplate = defaultConfig.clone();
activityTemplate.setReportType("activity");
activityTemplate.setColumns(Arrays.asList("user_id", "action", "timestamp", "ip_address"));
activityTemplate.setSortBy("timestamp");
templates.put("activity", activityTemplate);
}
// 基于已有模板创建新配置
public ReportConfiguration createFromTemplate(String templateName) {
ReportConfiguration template = templates.get(templateName);
if (template == null) {
throw new IllegalArgumentException("Template not found: " + templateName);
}
return template.clone();
}
// 基于默认配置创建新配置
public ReportConfiguration createDefault() {
return defaultConfig.clone();
}
}
// 使用原型模式
@RestController
@RequestMapping("/reports")
public class ReportController {
@Autowired
private ReportFactory reportFactory;
@GetMapping("/financial")
public String generateFinancialReport(@RequestParam Map<String, String> params) {
// 获取财务报表模板并自定义
ReportConfiguration config = reportFactory.createFromTemplate("financial");
// 根据请求参数自定义报表配置
if (params.containsKey("dateRange")) {
config.setDateRange(params.get("dateRange"));
}
// 使用配置生成报表...
return "Financial report generated with config: " + config;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
应用优势
- 避免反复执行初始化代码
- 提供配置模板,方便创建预定义对象
- 减少子类数量,通过复制实现对象变异
适配器模式 (Adapter Pattern)
模式概述
适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
SpringBoot应用
SpringBoot中的各种适配器广泛应用于MVC框架和第三方集成中。
实现示例
// 旧的支付服务接口
public interface LegacyPaymentService {
boolean processPayment(String accountNumber, double amount, String currency);
String getTransactionStatus(String transactionId);
}
// 旧的支付服务实现
@Service("legacyPaymentService")
public class LegacyPaymentServiceImpl implements LegacyPaymentService {
@Override
public boolean processPayment(String accountNumber, double amount, String currency) {
System.out.println("Processing payment using legacy system");
// 旧系统的支付处理逻辑
return true;
}
@Override
public String getTransactionStatus(String transactionId) {
// 旧系统获取交易状态的逻辑
return "COMPLETED";
}
}
// 新的支付接口
public interface ModernPaymentGateway {
PaymentResponse pay(PaymentRequest request);
TransactionStatus checkStatus(String reference);
}
// 支付请求和响应模型
@Data
public class PaymentRequest {
private String customerId;
private BigDecimal amount;
private String currencyCode;
private String paymentMethod;
private Map<String, String> metadata;
}
@Data
public class PaymentResponse {
private String referenceId;
private boolean successful;
private String message;
}
public enum TransactionStatus {
PENDING, PROCESSING, COMPLETED, FAILED, REFUNDED
}
// 适配器:将旧接口适配到新接口
@Component
public class LegacyPaymentAdapter implements ModernPaymentGateway {
private final LegacyPaymentService legacyService;
@Autowired
public LegacyPaymentAdapter(LegacyPaymentService legacyService) {
this.legacyService = legacyService;
}
@Override
public PaymentResponse pay(PaymentRequest request) {
// 将新的请求模型转换为旧接口参数
boolean result = legacyService.processPayment(
request.getCustomerId(),
request.getAmount().doubleValue(),
request.getCurrencyCode()
);
// 将旧接口结果转换为新的响应模型
PaymentResponse response = new PaymentResponse();
response.setSuccessful(result);
response.setReferenceId(UUID.randomUUID().toString());
response.setMessage(result ? "Payment processed successfully" : "Payment failed");
return response;
}
@Override
public TransactionStatus checkStatus(String reference) {
// 将旧接口的状态映射为新接口的枚举
String status = legacyService.getTransactionStatus(reference);
switch (status) {
case "COMPLETED":
return TransactionStatus.COMPLETED;
case "FAILED":
return TransactionStatus.FAILED;
case "IN_PROGRESS":
return TransactionStatus.PROCESSING;
default:
return TransactionStatus.PENDING;
}
}
}
// 使用新接口
@Service
public class CheckoutService {
private final ModernPaymentGateway paymentGateway;
@Autowired
public CheckoutService(ModernPaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
public void processCheckout(Cart cart, String customerId) {
// 创建支付请求
PaymentRequest request = new PaymentRequest();
request.setCustomerId(customerId);
request.setAmount(cart.getTotal());
request.setCurrencyCode("USD");
// 使用适配后的接口处理支付
PaymentResponse response = paymentGateway.pay(request);
if (response.isSuccessful()) {
// 处理成功逻辑
} else {
// 处理失败逻辑
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
应用优势
- 复用现有代码,避免重写
- 平滑过渡,新旧系统并行运行
- 分离客户代码和接口实现
装饰器模式 (Decorator Pattern)
模式概述
装饰器模式动态地给一个对象添加一些额外的职责,相比生成子类更为灵活。
SpringBoot应用
SpringBoot中的@Cacheable等注解就是装饰器模式的应用,对原有方法进行增强。
实现示例
// 基础接口
public interface NotificationService {
void send(String message, String recipient);
}
// 基础实现
@Service
@Primary
public class EmailNotificationService implements NotificationService {
@Override
public void send(String message, String recipient) {
System.out.println("Sending email to " + recipient + ": " + message);
// 实际发送邮件的逻辑
}
}
// 装饰器基类
public abstract class NotificationDecorator implements NotificationService {
protected NotificationService wrapped;
public NotificationDecorator(NotificationService wrapped) {
this.wrapped = wrapped;
}
}
// 日志装饰器
@Component
public class LoggingNotificationDecorator extends NotificationDecorator {
private final Logger logger = LoggerFactory.getLogger(LoggingNotificationDecorator.class);
public LoggingNotificationDecorator(NotificationService wrapped) {
super(wrapped);
}
@Override
public void send(String message, String recipient) {
logger.info("Sending notification to: {}", recipient);
long startTime = System.currentTimeMillis();
wrapped.send(message, recipient);
long endTime = System.currentTimeMillis();
logger.info("Notification sent in {}ms", (endTime - startTime));
}
}
// 重试装饰器
@Component
public class RetryNotificationDecorator extends NotificationDecorator {
private final Logger logger = LoggerFactory.getLogger(RetryNotificationDecorator.class);
private final int maxRetries;
public RetryNotificationDecorator(
@Qualifier("loggingNotificationDecorator") NotificationService wrapped,
@Value("${notification.max-retries:3}") int maxRetries) {
super(wrapped);
this.maxRetries = maxRetries;
}
@Override
public void send(String message, String recipient) {
int attempts = 0;
boolean sent = false;
while (!sent && attempts < maxRetries) {
try {
attempts++;
wrapped.send(message, recipient);
sent = true;
} catch (Exception e) {
logger.warn("Failed to send notification (attempt {}): {}",
attempts, e.getMessage());
if (attempts >= maxRetries) {
logger.error("Max retries reached, giving up");
throw e;
}
try {
// 指数退避
Thread.sleep((long) Math.pow(2, attempts) * 100);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
}
// 加密装饰器
@Component
public class EncryptionNotificationDecorator extends NotificationDecorator {
public EncryptionNotificationDecorator(
@Qualifier("retryNotificationDecorator") NotificationService wrapped) {
super(wrapped);
}
@Override
public void send(String message, String recipient) {
String encryptedMessage = encrypt(message);
wrapped.send(encryptedMessage, recipient);
}
private String encrypt(String message) {
// 加密逻辑
return "ENCRYPTED[" + message + "]";
}
}
// 装饰器配置
@Configuration
public class NotificationConfig {
@Bean
public NotificationService loggingNotificationDecorator(
@Qualifier("emailNotificationService") NotificationService emailService) {
return new LoggingNotificationDecorator(emailService);
}
@Bean
public NotificationService retryNotificationDecorator(
@Qualifier("loggingNotificationDecorator") NotificationService loggingDecorator,
@Value("${notification.max-retries:3}") int maxRetries) {
return new RetryNotificationDecorator(loggingDecorator, maxRetries);
}
@Bean
public NotificationService encryptionNotificationDecorator(
@Qualifier("retryNotificationDecorator") NotificationService retryDecorator) {
return new EncryptionNotificationDecorator(retryDecorator);
}
@Bean
@Primary
public NotificationService notificationService(
@Qualifier("encryptionNotificationDecorator") NotificationService encryptionDecorator) {
return encryptionDecorator;
}
}
// 使用装饰后的服务
@Service
public class UserService {
private final NotificationService notificationService;
@Autowired
public UserService(NotificationService notificationService) {
this.notificationService = notificationService;
}
public void notifyUser(User user, String message) {
// 这里使用的是经过多层装饰的服务:加密->重试->日志->邮件
notificationService.send(message, user.getEmail());
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
应用优势
- 动态添加功能,保持接口一致
- 符合开闭原则,无需修改原有代码
- 可按需组合多种增强能力
观察者模式 (Observer Pattern)
模式概述
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
SpringBoot应用
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;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
应用优势
- 松耦合,事件发布者无需知道谁在监听
- 支持一对多通知
- 可实现异步处理和事件分发
- 便于扩展新的监听者
策略模式 (Strategy Pattern)
模式概述
策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换,让算法的变化独立于使用它的客户。
SpringBoot应用
策略模式广泛用于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;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
应用优势
- 算法可以独立于使用它的客户而变化
- 消除条件判断语句
- 易于扩展新的策略
- 提高代码复用性
模板方法模式 (Template Method Pattern)
模式概述
模板方法模式定义了一个算法的骨架,将一些步骤延迟到子类中实现,使子类可以不改变算法结构的情况下重定义算法的某些步骤。
SpringBoot应用
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());
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
应用优势
- 封装不变部分,扩展可变部分
- 提取公共代码,减少重复
- 控制子类扩展点
- 遵循好莱坞原则:"别调用我们,我们会调用你"
责任链模式 (Chain of Responsibility Pattern)
模式概述
责任链模式为请求创建了一个接收者对象的链,请求会沿着这条链传递,直到有一个对象处理它为止。
SpringBoot应用
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);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
应用优势
- 降低耦合度,请求发送者和接收者解耦
- 动态组合处理器,灵活调整处理流程
- 符合单一职责原则,每个处理器专注于一项任务
- 易于添加新的处理器,扩展性好
命令模式 (Command Pattern)
模式概述
命令模式将请求封装成对象,使发出请求的责任和执行请求的责任分割开,支持请求排队、回退等功能。
SpringBoot应用
在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);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
应用优势
- 请求发送者和接收者解耦
- 支持撤销操作
- 可以组合命令实现复杂操作
- 便于实现事务和日志
状态模式 (State Pattern)
模式概述
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
SpringBoot应用
在业务流程处理、订单状态管理等场景常用状态模式。
实现示例
// 订单状态接口
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));
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
SpringContext持有类(用于在实体中获取Bean)
@Component
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
return context.getBean(clazz);
}
public static Object getBean(String name) {
return context.getBean(name);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
应用优势
- 封装状态相关行为,使代码更加清晰
- 新增状态只需要添加新类,不需要修改现有代码
- 消除条件判断语句
- 显式地表达状态转换规则
总结
在实际开发中,这些设计模式往往不是孤立使用的,而是相互配合,共同解决复杂的业务问题。掌握这些设计模式及其应用场景,能够帮助开发者设计出更加灵活、可维护、可扩展的应用。
最后,设计模式是工具而非目的,应根据实际问题选择合适的模式,避免过度设计。合理运用设计模式,才能真正提升代码质量和开发效率。
