设计模式-策略模式

策略模式

什么是策略模式?

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

核心思想:

将不同的算法(策略)封装成独立的类,这些类实现一个共同的接口。客户端可以根据需要选择并使用不同的策略,而无需修改客户端自身的代码。这使得算法的选择和实现变得灵活和可扩展。

简单来说,就像你有很多种出行方案(策略):

  • 坐公交车 (策略 A)

  • 骑自行车 (策略 B)

  • 打出租车 (策略 C)

你可以根据具体情况(如天气、距离、时间)选择一种最合适的出行方案,而选择方案的行为和具体方案的执行是分开的。

主要角色:

  1. 环境类 (Context):

    • 持有一个对策略对象的引用。

    • 它不直接执行算法,而是将请求委托给它所持有的策略对象。

    • 客户端通常通过环境类来调用具体的策略。

    • 可以提供一个方法来设置或切换当前的策略。

  2. 抽象策略 (Strategy):

    • 定义所有支持的算法的公共接口或抽象类。

    • 环境类通过这个接口调用具体策略类中定义的算法。

  3. 具体策略 (Concrete Strategy):

    • 实现了抽象策略接口或继承了抽象策略类的具体类。

    • 封装了具体的算法或行为。

    • 每个具体策略类代表一种特定的算法实现。

工作流程:

  1. 客户端创建一个具体策略对象。

  2. 客户端创建一个环境类对象,并将具体策略对象设置到环境类中。

  3. 当客户端需要执行某个操作时,它调用环境类的方法。

  4. 环境类将请求委托给它所持有的具体策略对象去执行。

  5. 具体策略对象执行其封装的算法,并返回结果(如果需要)。

代码示例 (Java):

假设我们要实现一个购物车结算功能,可以有不同的促销策略,如打折、满减。

复制代码
// 1. 抽象策略 (PromotionStrategy)
interface PromotionStrategy {
    double applyDiscount(double originalPrice);
}
​
// 2. 具体策略 (DiscountStrategy, FullReductionStrategy)
class DiscountStrategy implements PromotionStrategy {
    private double discountRate; // 例如 0.8 表示八折
​
    public DiscountStrategy(double discountRate) {
        this.discountRate = discountRate;
    }
​
    @Override
    public double applyDiscount(double originalPrice) {
        System.out.println("Applying discount strategy: " + (discountRate * 100) + "% off");
        return originalPrice * discountRate;
    }
}
​
class FullReductionStrategy implements PromotionStrategy {
    private double conditionAmount; // 满多少
    private double reductionAmount; // 减多少
​
    public FullReductionStrategy(double conditionAmount, double reductionAmount) {
        this.conditionAmount = conditionAmount;
        this.reductionAmount = reductionAmount;
    }
​
    @Override
    public double applyDiscount(double originalPrice) {
        System.out.println("Applying full reduction strategy: spend " + conditionAmount + ", get " + reductionAmount + " off");
        if (originalPrice >= conditionAmount) {
            return originalPrice - reductionAmount;
        }
        return originalPrice;
    }
}
​
class NoPromotionStrategy implements PromotionStrategy {
    @Override
    public double applyDiscount(double originalPrice) {
        System.out.println("No promotion applied.");
        return originalPrice;
    }
}
​
​
// 3. 环境类 (ShoppingCart)
class ShoppingCart {
    private PromotionStrategy promotionStrategy;
    private double originalPrice;
​
    public ShoppingCart(double originalPrice) {
        this.originalPrice = originalPrice;
        // 默认无促销
        this.promotionStrategy = new NoPromotionStrategy();
    }
​
    // 设置促销策略
    public void setPromotionStrategy(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }
​
    public double checkout() {
        return promotionStrategy.applyDiscount(originalPrice);
    }
}
​
// 客户端使用
public class Client {
    public static void main(String[] args) {
        // 场景1: 商品原价 100元,无促销
        ShoppingCart cart1 = new ShoppingCart(100.0);
        System.out.println("Cart 1 Final Price: " + cart1.checkout()); // 输出: No promotion applied. Cart 1 Final Price: 100.0
​
        System.out.println("--------------------");
​
        // 场景2: 商品原价 200元,使用八折促销
        ShoppingCart cart2 = new ShoppingCart(200.0);
        cart2.setPromotionStrategy(new DiscountStrategy(0.8));
        System.out.println("Cart 2 Final Price: " + cart2.checkout()); // 输出: Applying discount strategy: 80.0% off. Cart 2 Final Price: 160.0
​
        System.out.println("--------------------");
​
        // 场景3: 商品原价 300元,使用满250减50促销
        ShoppingCart cart3 = new ShoppingCart(300.0);
        cart3.setPromotionStrategy(new FullReductionStrategy(250, 50));
        System.out.println("Cart 3 Final Price: " + cart3.checkout()); // 输出: Applying full reduction strategy: spend 250.0, get 50.0 off. Cart 3 Final Price: 250.0
​
        System.out.println("--------------------");
​
        // 场景4: 商品原价 150元,使用满250减50促销 (不满足条件)
        ShoppingCart cart4 = new ShoppingCart(150.0);
        cart4.setPromotionStrategy(new FullReductionStrategy(250, 50));
        System.out.println("Cart 4 Final Price: " + cart4.checkout()); // 输出: Applying full reduction strategy: spend 250.0, get 50.0 off. Cart 4 Final Price: 150.0
    }
}

优点:

  1. 算法可以自由切换: 客户端可以根据需要动态地选择和切换不同的策略。

  2. 避免使用多重条件转移语句(if-else 或 switch-case): 将不同的行为封装到不同的策略类中,使得代码更清晰,避免了冗长的条件判断。

  3. 扩展性好: 增加新的策略非常容易,只需要添加一个新的具体策略类实现抽象策略接口即可,符合开闭原则。

  4. 策略类可以复用: 每个策略都是一个独立的对象,可以在不同的环境类中复用。

  5. 将算法的实现细节与客户端代码分离: 客户端只需要知道如何使用策略,而不需要关心策略的具体实现。

缺点:

  1. 客户端必须知道所有的策略类: 客户端需要了解有哪些可用的策略,并自己选择使用哪一个。这在一定程度上增加了客户端的复杂性。(可以通过结合工厂模式来隐藏具体策略类)。

  2. 会产生很多策略类: 如果策略很多,会导致类的数量增加。

适用场景:

  1. 一个系统需要在许多算法中选择一种时。 例如,文件压缩有多种算法(ZIP, RAR, GZIP),排序有多种算法(冒泡、快排、归并)。

  2. 如果一个对象有很多行为,而且这些行为在运行时根据状态而变化,可以使用策略模式将这些行为封装到不同的策略类中。

  3. 当一个类定义了多种行为,并且这些行为以多个条件语句的形式出现时。 策略模式可以将这些条件分支移入它们各自的策略类中,以代替这些条件语句。

  4. 当你想在不修改客户端代码的情况下,动态地改变对象的行为时。

  5. 当你想避免暴露复杂的、与算法相关的数据结构时。

与状态模式的区别:

策略模式和状态模式在结构上非常相似(都有一个环境类、一个抽象接口和多个具体实现类),但它们的意图不同:

  • 策略模式: 关注的是算法的选择和替换,客户端主动选择使用哪个策略。策略之间通常是平行的,可以互相替换。

  • 状态模式: 关注的是对象在不同状态下的行为变化,状态的转换通常是由对象内部条件或者外部事件触发的,客户端通常不直接选择状态。状态之间通常有明确的转换关系。

简单来说,策略模式是"我选择用什么方法做这件事",而状态模式是"我在什么状态下,就应该怎么做这件事"。

相关推荐
qqxhb10 分钟前
零基础设计模式——结构型模式 - 组合模式
设计模式·组合模式
孤独得猿11 分钟前
类的设计模式——单例、工厂以及建造者模式
单例模式·设计模式·建造者模式
杰克逊的日记4 小时前
java中的设计模式
java·开发语言·设计模式
qqxhb5 小时前
零基础设计模式——结构型模式 - 桥接模式
设计模式·桥接模式·抽象与实现分离
暴躁哥6 小时前
深入理解设计模式之命令模式
设计模式·命令模式
hstar95277 小时前
二十九、面向对象底层逻辑-SpringMVC九大组件之MultipartResolver接口设计
java·spring·设计模式·架构
hstar95277 小时前
三十、面向对象底层逻辑-SpringMVC九大组件之HandlerInterceptor接口设计
java·spring·设计模式·架构
带电的小王9 小时前
C++:设计模式--工厂模式
c++·设计模式·工厂模式
季鸢10 小时前
Java设计模式之代理模式详解
java·设计模式·代理模式
ErizJ13 小时前
Golang|etcd服务注册与发现 & 策略模式
golang·策略模式·etcd