策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。这种模式提供了用一系列可互换的算法或策略来封装算法族,并使它们可以相互替换。策略模式鼓励使用对象组合而不是继承来实现具有多种行为的系统。
以下是策略模式的组成部分以及一个详细的Java示例:
组成部分:
-
策略接口 (Strategy):定义所有支持的算法的公共接口。通常是一个接口或抽象类,它规定了所有具体策略类需要实现的方法。
public interface PaymentStrategy { void pay(double amount); }
-
具体策略类 (Concrete Strategies):实现策略接口,提供具体的算法实现。每个具体策略代表一个可选的算法或行为。
public class CreditCardPayment implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("Charging " + amount + " to credit card."); } } public class PayPalPayment implements PaymentStrategy { @Override public void pay(double amount) { System.out.println("Paying " + amount + " via PayPal."); } } // 可以有更多其他支付方式的实现,如ApplePayPayment、BankTransferPayment等
-
上下文 (Context):维护一个对策略对象的引用,负责与策略对象交互,并在需要的时候调用策略对象的方法。上下文不关心具体的策略实现,只知道它使用的是策略接口。
public class ShoppingCart { private List<Item> items; private PaymentStrategy paymentStrategy; public ShoppingCart(PaymentStrategy paymentStrategy) { this.paymentStrategy = paymentStrategy; } public void checkout() { double totalAmount = calculateTotal(); paymentStrategy.pay(totalAmount); System.out.println("Checkout completed using selected payment method."); } // 其他相关购物车逻辑... }
使用示例:
客户端代码可以根据需求动态选择并注入合适的策略。
public class Client {
public static void main(String[] args) {
ShoppingCart cartWithCreditCard = new ShoppingCart(new CreditCardPayment());
cartWithCreditCard.checkout(); // 输出:Charging X to credit card. Checkout completed using selected payment method.
ShoppingCart cartWithPayPal = new ShoppingCart(new PayPalPayment());
cartWithPayPal.checkout(); // 输出:Paying X via PayPal. Checkout completed using selected payment method.
}
}
在这个例子中,ShoppingCart
是上下文,它依赖于 PaymentStrategy
接口。根据用户选择的支付方式(信用卡或 PayPal),客户端创建相应的 ShoppingCart
实例,注入对应的支付策略。在结账时,ShoppingCart
调用 pay
方法执行实际的支付操作,但并不关心具体是如何实现的。
优点:
- 开放封闭原则:添加新支付方式(即策略)时,不需要修改现有代码,只需新增一个实现
PaymentStrategy
的类即可。 - 单一职责原则:支付逻辑被封装在各自的策略类中,上下文专注于处理购物车的核心业务逻辑。
- 易扩展:策略模式使得算法或行为易于替换,只需更改上下文持有的策略对象即可。
缺点:
- 策略类数量增加:随着可选策略的增多,类的数量也会增加,可能需要更多的管理。
- 策略需要暴露:所有的策略类都需要对外可见,以便客户端能够创建并传递给上下文。
Spring 源码中的策略模式应用
Spring 框架中广泛运用了策略模式,以下是一些实例:
-
数据源配置:
Spring 支持多种数据源类型(如 JDBC、JNDI、HikariCP 等)。这些数据源实现类都遵循DataSource
接口(或其子接口),Spring 根据配置文件中的设置选择合适的数据源策略。客户端代码(如 DAO 层)仅依赖DataSource
接口进行数据库操作,无需关心底层数据源的具体实现。 -
事务管理:
Spring 提供了声明式事务管理功能,允许用户通过配置选择不同的事务管理器策略,如DataSourceTransactionManager
(针对 JDBC 数据源)、JtaTransactionManager
(用于全局 JTA 事务)等。这些事务管理器都实现了PlatformTransactionManager
接口,应用代码通过该接口与事务管理器交互,而无需关注具体的事务处理逻辑。 -
视图解析:
在 Spring MVC 中,ViewResolver
接口及其各种实现(如InternalResourceViewResolver
、TilesViewResolver
、ThymeleafViewResolver
等)构成了策略模式。Spring 根据配置和请求信息选择合适的视图解析器来决定如何渲染视图,而控制器只需返回视图名,无需知道具体的视图技术细节。 -
消息转换:
Spring 消息转换体系中,MessageConverter
接口及其实现类(如MappingJackson2HttpMessageConverter
、StringHttpMessageConverter
等)构成了策略模式。Spring MVC 或 Spring WebFlux 在处理 HTTP 请求和响应时,根据请求的 Content-Type 和 Accept 头部,以及配置,选择合适的转换器来序列化或反序列化请求/响应体。 -
缓存支持:
Spring Cache 提供了对多种缓存提供商(如 EhCache、Redis、Guava 等)的支持。这些缓存适配器都实现了CacheManager
和Cache
接口,应用程序只需通过统一的缓存 API 与之交互,而具体的缓存存储策略由配置的 CacheManager 实现决定。
这些例子展示了 Spring 如何利用策略模式来提供高度可配置、可扩展的服务,允许用户根据项目需求选择或更换具体的实现策略,而无需改动核心业务逻辑。这极大地增强了框架的灵活性和适应性。