引言
在当今的软件开发领域,Spring Boot 以其高效、便捷的特性成为构建 Java 应用程序的热门框架。而设计模式作为软件开发中的宝贵经验总结,能够显著提升代码的可维护性、可扩展性和可复用性。本文将深入探讨几种常用设计模式在 Spring Boot 项目中的实际应用,通过具体案例帮助读者更好地理解和掌握这些设计模式在实际开发中的运用技巧。
一、工厂模式
场景描述
假设我们正在开发一个电商系统,其中有多种不同类型的订单,如普通订单、促销订单、团购订单等。每种订单在处理时都有一些独特的逻辑,例如促销订单需要计算优惠金额,团购订单需要处理成团逻辑等。我们可以使用工厂模式来根据订单类型创建不同的订单处理对象。
代码实现
1.定义订单处理接口
public interface OrderProcessor { void processOrder(); }
2.创建具体的订单处理类
- 普通订单处理类
@Component public class NormalOrderProcessor implements OrderProcessor { @Override public void processOrder() { System.out.println("Processing normal order..."); } }
- 促销订单处理类
@Component public class PromotionOrderProcessor implements OrderProcessor { @Override public void processOrder() { System.out.println("Processing promotion order, calculating discounts..."); } }
3.创建订单工厂类
@Component public class OrderFactory { @Autowired private Map<String, OrderProcessor> orderProcessorMap; public OrderProcessor getOrderProcessor(String orderType) { return orderProcessorMap.get(orderType); } }
4.在服务层使用工厂类
@Service public class OrderService { @Autowired private OrderFactory orderFactory; public void process(String orderType) { OrderProcessor orderProcessor = orderFactory.getOrderProcessor(orderType); if (orderProcessor != null) { orderProcessor.processOrder(); } else { System.out.println("No suitable order processor found for type: " + orderType); } } }
优势分析
通过工厂模式,我们将对象的创建和使用分离,当需要新增订单类型时,只需创建新的订单处理类并在配置中注册,无需修改大量现有代码,提高了系统的可扩展性。
二、单例模式
场景描述
在 Spring Boot 项目中,经常会有一些资源或对象只需要一个实例,例如数据库连接池、日志记录器等。以日志记录器为例,我们希望整个应用程序中只有一个日志记录器实例,以确保日志记录的一致性和高效性。
代码实现
1.使用 Spring 的注解实现单例
@Component public class CustomLogger { private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CustomLogger.class); public void logMessage(String message) { logger.info(message); } }
在 Spring 中,默认情况下,通过@Component注解创建的 Bean 就是单例模式。当其他组件需要使用CustomLogger时,直接注入即可。
@Service public class SomeService { @Autowired private CustomLogger customLogger; public void doSomething() { customLogger.logMessage("Service is doing something..."); } }
优势分析
单例模式确保了系统中特定资源或对象的唯一性,避免了资源的重复创建和浪费,提高了系统性能和资源利用率,同时也方便了对共享资源的管理和维护。
三、代理模式
场景描述
假设我们有一个业务方法,在调用该方法前后需要添加一些通用的逻辑,比如权限验证、日志记录等。我们可以使用代理模式来实现这些横切关注点,而无需在每个业务方法中重复编写相同的代码。
代码实现
1.定义业务接口
public interface UserService { void doBusinessLogic(); }
2.创建真实业务类
@Service public class UserServiceImpl implements UserService { @Override public void doBusinessLogic() { System.out.println("Doing business logic..."); } }
3.创建代理类
@Aspect @Component public class UserServiceProxy { @Around("execution(* com.example.demo.service.UserService.doBusinessLogic(..))") public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Before business logic - checking permissions"); Object result = joinPoint.proceed(); System.out.println("After business logic - logging"); return result; } }
优势分析
代理模式将核心业务逻辑与辅助性的横切逻辑分离,使代码更加清晰、可维护。通过代理类,我们可以方便地在不修改原有业务代码的基础上添加新的功能,符合开闭原则。
四、策略模式
场景描述
继续以电商系统为例,系统中有多种不同的运费计算方式,如按重量计算、按订单金额计算、固定运费等。为了能够灵活地切换和管理这些运费计算方式,我们可以运用策略模式。
代码实现
1.定义运费计算策略接口
public interface ShippingFeeStrategy { double calculateShippingFee(double weight, double orderAmount); }
2.创建具体的运费计算策略类
- 按重量计算运费策略类
@Component public class WeightBasedShippingStrategy implements ShippingFeeStrategy { @Override public double calculateShippingFee(double weight, double orderAmount) { // 假设每千克运费为10元 return weight * 10; } }
- 按订单金额计算运费策略类
@Component public class OrderAmountBasedShippingStrategy implements ShippingFeeStrategy { @Override public double calculateShippingFee(double weight, double orderAmount) { // 假设订单金额满100免运费,否则收取10元运费 return orderAmount >= 100? 0 : 10; } }
- 固定运费策略类
@Component public class FixedShippingStrategy implements ShippingFeeStrategy { @Override public double calculateShippingFee(double weight, double orderAmount) { // 固定运费为5元 return 5; } }
3.创建运费计算服务,使用策略模式
@Service public class ShippingFeeService { @Autowired private Map<String, ShippingFeeStrategy> shippingFeeStrategyMap; public double calculate(String strategyType, double weight, double orderAmount) { ShippingFeeStrategy strategy = shippingFeeStrategyMap.get(strategyType); if (strategy != null) { return strategy.calculateShippingFee(weight, orderAmount); } else { throw new IllegalArgumentException("No suitable shipping fee strategy found for type: " + strategyType); } } }
优势分析
策略模式使得不同的运费计算算法可以独立变化,符合开闭原则。当需要新增运费计算方式时,只需创建新的策略类并实现接口,然后在配置中注册即可,无需修改现有业务代码,大大提高了系统的灵活性和可维护性。同时,不同的策略类可以被复用,提高了代码的复用性。
补充
也可以自定义Match接口实现策略模式,大致思路如下:
1.定义Match接口
public interface Match<T> { boolean match(T var1); }
2.业务接口继承Match接口
public interface BusinessHandler extends Match<String> { /** * 业务执行方法 * * @param context 上下文 */ void execute(BusinessContext context); }
3.特定策略类实现业务接口
类一:
@Slf4j @Component public class ExactMatchSort implements BusinessHandler { @Setter(onMethod_ = @Autowired) BusinessService businessService; /** * {@inheritDoc} */ @Override public boolean match(String value) { return RuleEnum.EXACT_MATCH.getCode().equals(value); } /** * {@inheritDoc} */ @Override public void execute(BusinessContext context) { // 自定义业务逻辑 businessService.exactMatch(context); } }
类二:
@Slf4j @Component public class FuzzyMatchSort implements BusinessHandler { @Setter(onMethod_ = @Autowired) BusinessService businessService; /** * {@inheritDoc} */ @Override public boolean match(String value) { return RuleEnum.FUZZY_MATCH.getCode().equals(value); } /** * {@inheritDoc} */ @Override public void execute(BusinessContext context) { // 自定义业务逻辑 businessService.fuzzyMatch(context); } }
4.定义抽象策略管理器
public abstract class AbstractProcessorManage<T, P extends Match<T>> { private List<P> processorList; public AbstractProcessorManage() { } @Autowired public void setProcessorList(List<P> processorList) { this.processorList = processorList; } public abstract String getCannotMatchMessage(); public P getProcessor(T t) { for(P p : this.processorList) { if (p.match(t)) { return p; } } throw new RuntimeException(this.getCannotMatchMessage()); } }
5.定义业务策略管理器
/** * 策略管理器 */ @Component public class BusinessManger extends AbstractProcessorManage<String, BusinessHandler> { /** * {@inheritDoc} */ @Override public String getCannotMatchMessage() { return "非法的策略"; } }
6.业务流程调用
/** * 业务执行类 * */ @Slf4j @Component public class StockFilterManager { @Setter(onMethod_ = @Autowired) private BusinessManger businessManger; private void businessExcute(BusinessContext context) { businessManger.getProcessor(context.value).execute(context); } }
这仅是基础架构,也可以在内层嵌套更多的设计模式,以保证代码的可读性与可维护性。
结论
通过以上在 Spring Boot 项目中的实战案例,我们看到了工厂模式、单例模式、代理模式以及策略模式在不同场景下的应用及其带来的显著优势。在实际项目开发中,合理运用设计模式能够极大地提升代码质量,使项目更加健壮、灵活和易于维护。希望读者通过本文的学习,能够在自己的 Spring Boot 项目中熟练运用这些设计模式,打造出更优秀的软件系统。