设计模式-策略模式

策略模式

什么是策略模式?

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

核心思想:

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

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

  • 坐公交车 (策略 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. 当你想避免暴露复杂的、与算法相关的数据结构时。

与状态模式的区别:

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

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

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

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

相关推荐
触底反弹2 小时前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
张小姐的猫19 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范
杨充1 天前
6.设计原则的全景图
设计模式·开源·全栈
杨充1 天前
2.面向对象的特性
设计模式
杨充1 天前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充1 天前
8.反模式与坏味道
设计模式·开源·代码规范
杨充1 天前
3.接口vs抽象类比较
设计模式