定义
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。
以下是策略模式的主要特点和定义:
主要角色
-
Context(环境类) :
- 持有一个策略对象的引用。
- 负责调用策略对象的算法。
-
Strategy(抽象策略类) :
- 定义了所有支持算法的公共接口。
-
ConcreteStrategy(具体策略类) :
- 实现了抽象策略类定义的接口,提供具体的算法实现。
业务
假设我们正在开发一个电商系统,需要根据不同的促销活动计算商品的价格。我们可以使用策略模式来实现这个功能。
classDiagram
class PricingStrategy {
+calculatePrice(double) : double
}
class NormalPricingStrategy {
+calculatePrice(double) : double
}
class DiscountPricingStrategy {
-double discountPercentage
+DiscountPricingStrategy(double)
+calculatePrice(double) : double
}
class FullReductionPricingStrategy {
-double fullPrice
-double reductionAmount
+FullReductionPricingStrategy(double, double)
+calculatePrice(double) : double
}
class ShoppingCart {
-PricingStrategy pricingStrategy
+ShoppingCart(PricingStrategy)
+setPricingStrategy(PricingStrategy) : void
+calculateTotalPrice(double[]) : double
}
PricingStrategy <|-- NormalPricingStrategy
PricingStrategy <|-- DiscountPricingStrategy
PricingStrategy <|-- FullReductionPricingStrategy
ShoppingCart "1" --> "1" PricingStrategy
一、定义抽象策略类(Strategy)
interface PricingStrategy {
double calculatePrice(double originalPrice);
}
二、定义具体策略类(ConcreteStrategy)
- 正常价格策略:
class NormalPricingStrategy implements PricingStrategy {
@Override
public double calculatePrice(double originalPrice) {
return originalPrice;
}
}
- 折扣价格策略:
class DiscountPricingStrategy implements PricingStrategy {
private double discountPercentage;
public DiscountPricingStrategy(double discountPercentage) {
this.discountPercentage = discountPercentage;
}
@Override
public double calculatePrice(double originalPrice) {
return originalPrice * (1 - discountPercentage / 100);
}
}
- 满减价格策略:
class FullReductionPricingStrategy implements PricingStrategy {
private double fullPrice;
private double reductionAmount;
public FullReductionPricingStrategy(double fullPrice, double reductionAmount) {
this.fullPrice = fullPrice;
this.reductionAmount = reductionAmount;
}
@Override
public double calculatePrice(double originalPrice) {
if (originalPrice >= fullPrice) {
return originalPrice - reductionAmount;
}
return originalPrice;
}
}
三、定义环境类(Context)
class ShoppingCart {
private PricingStrategy pricingStrategy;
public ShoppingCart(PricingStrategy pricingStrategy) {
this.pricingStrategy = pricingStrategy;
}
public void setPricingStrategy(PricingStrategy pricingStrategy) {
this.pricingStrategy = pricingStrategy;
}
public double calculateTotalPrice(double[] itemPrices) {
double totalPrice = 0;
for (double price : itemPrices) {
totalPrice += pricingStrategy.calculatePrice(price);
}
return totalPrice;
}
}
四、使用策略模式
public class StrategyPatternExample {
public static void main(String[] args) {
double[] itemPrices = {100.0, 50.0, 80.0};
ShoppingCart cart = new ShoppingCart(new NormalPricingStrategy());
System.out.println("Normal pricing total: " + cart.calculateTotalPrice(itemPrices));
cart.setPricingStrategy(new DiscountPricingStrategy(20));
System.out.println("With 20% discount total: " + cart.calculateTotalPrice(itemPrices));
cart.setPricingStrategy(new FullReductionPricingStrategy(200.0, 50.0));
System.out.println("With full reduction total: " + cart.calculateTotalPrice(itemPrices));
}
}
在这个例子中,PricingStrategy是抽象策略类,定义了计算价格的接口。NormalPricingStrategy、DiscountPricingStrategy和FullReductionPricingStrategy是具体策略类,实现了不同的价格计算策略。ShoppingCart是环境类,它持有一个策略对象,并将计算总价的任务委托给策略对象来执行。通过这种方式,我们可以在运行时根据不同的促销活动选择不同的价格计算策略,实现了策略模式的设计。
框架中的使用
spring
在 Spring 框架中,策略模式有很多应用场景。
一、事务管理
Spring 的事务管理可以看作是策略模式的一种应用。不同的事务传播行为(PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS 等)可以被视为不同的策略。Spring 根据配置选择合适的事务传播策略来管理数据库事务。
例如:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void saveUser(User user) {
userRepository.save(user);
}
}
这里,@Transactional注解中的不同传播行为就是不同的策略,Spring 根据这些配置来决定如何管理事务。
二、日志记录
Spring 中的日志框架(如 Logback、Log4j2 等)也可以看作是策略模式的应用。可以根据不同的需求选择不同的日志级别(DEBUG、INFO、WARN、ERROR 等),这就相当于选择不同的日志记录策略。
例如:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class SomeService {
private static final Logger logger = LoggerFactory.getLogger(SomeService.class);
public void doSomething() {
logger.info("Starting method doSomething.");
// some business logic
logger.debug("Some debug information.");
if (someCondition) {
logger.warn("Warning message.");
}
logger.error("An error occurred.");
}
}
这里,根据不同的情况选择不同的日志级别来记录信息,就是在使用不同的策略。
三、缓存管理
Spring 的缓存框架(如 Spring Cache)也体现了策略模式。可以选择不同的缓存实现策略,如基于内存的缓存、基于 Redis 的缓存等。
例如:
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
@Cacheable(value = "products", cacheManager = "redisCacheManager")
public Product getProductById(Long id) {
// fetch product from database or other source
return product;
}
}
这里,通过配置不同的cacheManager来选择不同的缓存策略。
综上所述,Spring 框架在很多地方都应用了策略模式,使得开发者可以根据具体的需求选择不同的策略来实现各种功能,提高了系统的灵活性和可扩展性。
总结
使用场景
-
多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
- 例如,一个图形绘制程序可以根据用户的选择使用不同的绘制算法(如直线绘制算法、圆形绘制算法、矩形绘制算法等)。
-
需要在不同情况下使用不同的算法,并且这些算法可以在未来进行扩展。
- 比如在一个电商系统中,根据不同的促销活动,可以使用不同的折扣计算策略。
优点
-
策略模式提供了一种替代继承的方法,实现了代码的可维护性和可扩展性。
- 避免了使用大量的条件语句来判断不同的行为,使得代码更加清晰和易于维护。
-
策略模式可以在运行时动态地选择算法,提高了系统的灵活性。
- 可以根据不同的条件选择不同的策略,而不需要修改客户端代码。
-
策略模式将算法的实现和使用分离,使得算法的变化不会影响到使用算法的客户端。
缺点
-
客户端必须了解所有的策略类,并决定使用哪一个策略。
- 这可能会增加客户端的复杂性,特别是当策略类较多时。
-
策略模式会增加系统中类的数量。
- 对于每一个具体的策略都需要创建一个类,这可能会导致系统变得复杂。