【策略模式】

81 阅读5分钟

定义

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

以下是策略模式的主要特点和定义:

主要角色

  1. Context(环境类)

    • 持有一个策略对象的引用。
    • 负责调用策略对象的算法。
  2. Strategy(抽象策略类)

    • 定义了所有支持算法的公共接口。
  3. 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)

  1. 正常价格策略:
class NormalPricingStrategy implements PricingStrategy {
    @Override
    public double calculatePrice(double originalPrice) {
        return originalPrice;
    }
}
  1. 折扣价格策略:
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);
    }
}
  1. 满减价格策略:
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是抽象策略类,定义了计算价格的接口。NormalPricingStrategyDiscountPricingStrategyFullReductionPricingStrategy是具体策略类,实现了不同的价格计算策略。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 框架在很多地方都应用了策略模式,使得开发者可以根据具体的需求选择不同的策略来实现各种功能,提高了系统的灵活性和可扩展性。

总结

使用场景

  1. 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。

    • 例如,一个图形绘制程序可以根据用户的选择使用不同的绘制算法(如直线绘制算法、圆形绘制算法、矩形绘制算法等)。
  2. 需要在不同情况下使用不同的算法,并且这些算法可以在未来进行扩展。

    • 比如在一个电商系统中,根据不同的促销活动,可以使用不同的折扣计算策略。

优点

  1. 策略模式提供了一种替代继承的方法,实现了代码的可维护性和可扩展性。

    • 避免了使用大量的条件语句来判断不同的行为,使得代码更加清晰和易于维护。
  2. 策略模式可以在运行时动态地选择算法,提高了系统的灵活性。

    • 可以根据不同的条件选择不同的策略,而不需要修改客户端代码。
  3. 策略模式将算法的实现和使用分离,使得算法的变化不会影响到使用算法的客户端。

缺点

  1. 客户端必须了解所有的策略类,并决定使用哪一个策略。

    • 这可能会增加客户端的复杂性,特别是当策略类较多时。
  2. 策略模式会增加系统中类的数量。

    • 对于每一个具体的策略都需要创建一个类,这可能会导致系统变得复杂。