23种设计模式之策略模式

1.策略模式的基础使用

策略模式是一种行为型设计模式,核心思想是将算法(或行为)封装为独立的策略类,使它们可以互相替换,从而让算法的变化独立于使用算法的客户端 。这种模式能有效解决代码中大量if-elseswitch判断的问题,符合 "开闭原则"(对扩展开放,对修改关闭)。

策略模式的核心角色

  1. 抽象策略(Strategy):定义所有具体策略的公共接口(或抽象类),声明策略执行的方法。
  2. 具体策略(Concrete Strategy):实现抽象策略接口,封装具体的算法逻辑。
  3. 环境(Context):持有策略对象的引用,负责调用策略的方法(不直接实现算法,而是委托给策略对象)。

代码案例:支付方式选择场景

假设一个电商系统需要支持多种支付方式(信用卡、支付宝、微信支付),且未来可能新增其他支付方式。使用策略模式可以灵活切换支付方式,无需修改核心逻辑。

1. 定义抽象策略(支付策略接口)

抽象策略接口定义所有支付方式的统一规范(此处方法pay)。

复制代码
// 抽象策略:支付策略接口
public interface PaymentStrategy {
    // 支付方法(参数为支付金额)
    void pay(double amount);
}
2. 实现具体策略(具体支付方式)

每种支付方式作为具体策略,实现PaymentStrategy接口,封装各自的支付逻辑。

复制代码
// 具体策略1:信用卡支付
public class CreditCardPayment implements PaymentStrategy {
    // 信用卡相关信息(实际场景中需加密处理)
    private String cardNumber;
    private String cardHolderName;

    public CreditCardPayment(String cardNumber, String cardHolderName) {
        this.cardNumber = cardNumber;
        this.cardHolderName = cardHolderName;
    }

    @Override
    public void pay(double amount) {
        System.out.printf("使用信用卡支付:卡号%s(持卡人:%s),金额:%.2f元%n",
                maskCardNumber(cardNumber), cardHolderName, amount);
    }

    // 辅助方法:隐藏卡号中间位数(安全处理)
    private String maskCardNumber(String cardNumber) {
        if (cardNumber.length() < 16) return cardNumber;
        return cardNumber.substring(0, 4) + " **** **** " + cardNumber.substring(12);
    }
}

// 具体策略2:支付宝支付
public class AlipayPayment implements PaymentStrategy {
    private String alipayAccount; // 支付宝账号(手机号或邮箱)

    public AlipayPayment(String alipayAccount) {
        this.alipayAccount = alipayAccount;
    }

    @Override
    public void pay(double amount) {
        System.out.printf("使用支付宝支付:账号%s,金额:%.2f元%n", alipayAccount, amount);
    }
}

// 具体策略3:微信支付
public class WechatPayment implements PaymentStrategy {
    private String wechatId; // 微信账号(微信号或手机号)

    public WechatPayment(String wechatId) {
        this.wechatId = wechatId;
    }

    @Override
    public void pay(double amount) {
        System.out.printf("使用微信支付:账号%s,金额:%.2f元%n", wechatId, amount);
    }
}
3. 定义环境类(购物车)

环境类持有策略对象的引用,负责调用策略的方法(不关心具体支付逻辑,只委托给策略)。

复制代码
// 环境类:购物车(负责使用支付策略)
public class ShoppingCart {
    // 持有支付策略的引用
    private PaymentStrategy paymentStrategy;

    // 设置支付策略(允许动态切换)
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    // 结算(委托给策略对象执行支付)
    public void checkout(double totalAmount) {
        if (paymentStrategy == null) {
            throw new IllegalStateException("请先设置支付方式");
        }
        paymentStrategy.pay(totalAmount);
    }
}
4. 客户端使用(测试代码)

客户端根据需求选择具体策略,通过环境类调用策略方法,无需关心策略的实现细节。

复制代码
public class Client {
    public static void main(String[] args) {
        // 创建购物车(环境对象)
        ShoppingCart cart = new ShoppingCart();

        // 场景1:使用信用卡支付
        PaymentStrategy creditCard = new CreditCardPayment("6222021234567890123", "张三");
        cart.setPaymentStrategy(creditCard);
        cart.checkout(399.99); // 输出:使用信用卡支付:卡号6222 **** **** 0123(持卡人:张三),金额:399.99元

        // 场景2:切换为支付宝支付
        PaymentStrategy alipay = new AlipayPayment("zhangsan@163.com");
        cart.setPaymentStrategy(alipay);
        cart.checkout(159.50); // 输出:使用支付宝支付:账号zhangsan@163.com,金额:159.50元

        // 场景3:切换为微信支付
        PaymentStrategy wechat = new WechatPayment("wx_zhangsan123");
        cart.setPaymentStrategy(wechat);
        cart.checkout(99.00); // 输出:使用微信支付:账号wx_zhangsan123,金额:99.00元
    }
}

策略模式的优点

  1. 灵活性高:客户端可动态切换策略(如示例中切换支付方式),无需修改环境类代码。
  2. 避免冗余判断 :用策略类替换if-elseswitch,减少代码复杂度。
  3. 易于扩展:新增策略只需实现抽象接口(如新增 "银联支付"),符合开闭原则。

2.策略模式的嵌套使用

下面以电商订单价格计算场景为例,展示策略模式的嵌套使用。在该场景中,订单价格计算策略会嵌套折扣策略,而折扣策略内部又可能包含组合折扣策略,形成多层策略嵌套。

场景说明

电商订单的最终价格计算涉及:

  1. 基础价格计算策略(常规价 / 会员价)
  2. 折扣策略(嵌套在基础计算中):
    • 百分比折扣
    • 固定金额折扣
    • 组合折扣(嵌套多个子折扣策略)

代码实现

1. 折扣策略接口(内层策略)

定义折扣计算的抽象行为,所有具体折扣策略需实现此接口。

复制代码
/**
 * 折扣策略接口(内层策略)
 */
public interface DiscountStrategy {
    // 计算折扣后价格(参数:原价)
    double calculateDiscount(double originalPrice);
}
2. 具体折扣策略(内层策略实现)

包括基础折扣和组合折扣(组合折扣会嵌套其他折扣策略)。

复制代码
/**
 * 百分比折扣(如9折)
 */
public class PercentageDiscount implements DiscountStrategy {
    private double percentage; // 折扣比例(0.9代表9折)

    public PercentageDiscount(double percentage) {
        this.percentage = percentage;
    }

    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice * percentage;
    }
}

/**
 * 固定金额折扣(如减50元)
 */
public class FixedDiscount implements DiscountStrategy {
    private double fixedAmount; // 固定减免金额

    public FixedDiscount(double fixedAmount) {
        this.fixedAmount = fixedAmount;
    }

    @Override
    public double calculateDiscount(double originalPrice) {
        // 确保折扣后价格不低于0
        return Math.max(originalPrice - fixedAmount, 0);
    }
}

/**
 * 组合折扣(嵌套多个子折扣策略,按顺序叠加)
 */
public class CombinedDiscount implements DiscountStrategy {
    private List<DiscountStrategy> discountStrategies; // 嵌套的子折扣策略

    public CombinedDiscount(List<DiscountStrategy> discountStrategies) {
        this.discountStrategies = discountStrategies;
    }

    @Override
    public double calculateDiscount(double originalPrice) {
        double price = originalPrice;
        // 依次应用所有子折扣策略(策略嵌套)
        for (DiscountStrategy strategy : discountStrategies) {
            price = strategy.calculateDiscount(price);
        }
        return price;
    }
}
3. 价格计算策略接口(外层策略)

定义订单价格计算的抽象行为,依赖折扣策略(内层策略)。

复制代码
/**
 * 价格计算策略接口(外层策略)
 */
public interface PriceCalculationStrategy {
    // 计算订单最终价格(参数:商品原价总和、折扣策略)
    double calculateFinalPrice(double totalOriginalPrice, DiscountStrategy discountStrategy);
}
4. 具体价格计算策略(外层策略实现)

包括常规价计算和会员价计算,均会嵌套使用折扣策略。

复制代码
/**
 * 常规价格计算策略(无基础优惠,直接应用折扣)
 */
public class RegularPriceStrategy implements PriceCalculationStrategy {
    @Override
    public double calculateFinalPrice(double totalOriginalPrice, DiscountStrategy discountStrategy) {
        // 嵌套使用折扣策略
        return discountStrategy.calculateDiscount(totalOriginalPrice);
    }
}

/**
 * 会员价格计算策略(基础价先打9.5折,再应用其他折扣)
 */
public class MemberPriceStrategy implements PriceCalculationStrategy {
    @Override
    public double calculateFinalPrice(double totalOriginalPrice, DiscountStrategy discountStrategy) {
        // 1. 先应用会员基础折扣(9.5折)
        double memberPrice = totalOriginalPrice * 0.95;
        // 2. 再嵌套使用外部传入的折扣策略(如促销折扣)
        return discountStrategy.calculateDiscount(memberPrice);
    }
}
5. 订单上下文类(使用策略)

封装策略的调用,对外提供统一的价格计算入口。

复制代码
/**
 * 订单类(策略上下文)
 */
public class Order {
    private double totalOriginalPrice; // 商品原价总和
    private PriceCalculationStrategy calculationStrategy; // 外层价格计算策略
    private DiscountStrategy discountStrategy; // 内层折扣策略

    public Order(double totalOriginalPrice, 
                 PriceCalculationStrategy calculationStrategy, 
                 DiscountStrategy discountStrategy) {
        this.totalOriginalPrice = totalOriginalPrice;
        this.calculationStrategy = calculationStrategy;
        this.discountStrategy = discountStrategy;
    }

    // 计算最终价格(委托给策略)
    public double getFinalPrice() {
        return calculationStrategy.calculateFinalPrice(totalOriginalPrice, discountStrategy);
    }
}
6. 测试代码

演示不同策略组合(包括多层嵌套)的效果。

复制代码
public class StrategyNestingDemo {
    public static void main(String[] args) {
        double originalPrice = 1000; // 商品原价总和1000元

        // 场景1:常规价格 + 9折优惠
        Order order1 = new Order(
            originalPrice,
            new RegularPriceStrategy(),
            new PercentageDiscount(0.9)
        );
        System.out.println("常规价+9折:" + order1.getFinalPrice()); // 900.0


        // 场景2:会员价格 + 减200元优惠
        Order order2 = new Order(
            originalPrice,
            new MemberPriceStrategy(),
            new FixedDiscount(200)
        );
        System.out.println("会员价+减200:" + order2.getFinalPrice()); // 750.0(1000*0.95=950,950-200=750)


        // 场景3:会员价格 + 组合折扣(先9折再减100元)
        List<DiscountStrategy> combined = new ArrayList<>();
        combined.add(new PercentageDiscount(0.9)); // 子折扣1:9折
        combined.add(new FixedDiscount(100));      // 子折扣2:减100
        Order order3 = new Order(
            originalPrice,
            new MemberPriceStrategy(),
            new CombinedDiscount(combined) // 组合折扣(嵌套子策略)
        );
        System.out.println("会员价+组合折扣:" + order3.getFinalPrice()); 
        // 计算过程:1000*0.95=950 → 950*0.9=855 → 855-100=755.0
    }
}

嵌套关系说明

  1. 外层策略(PriceCalculationStrategy)依赖内层策略(DiscountStrategy),形成第一层嵌套。
  2. 内层策略中的CombinedDiscount又依赖多个DiscountStrategy,形成第二层嵌套。
  3. 策略之间通过组合关系实现嵌套,而非继承,符合 "多用组合少用继承" 的设计原则。

优势

  • 灵活性:可动态替换外层价格策略和内层折扣策略,且支持无限层级的策略嵌套。
  • 可扩展性:新增折扣类型(如满减、第二件半价)只需实现DiscountStrategy,无需修改现有代码。
  • 可读性:每个策略职责单一,嵌套关系通过组合显式表达,逻辑清晰。
相关推荐
数据知道5 小时前
Go语言设计模式:建造者模式详解
设计模式·golang·建造者模式
崎岖Qiu5 小时前
【设计模式笔记11】:简单工厂模式优缺分析
java·笔记·设计模式·简单工厂模式
你的人类朋友15 小时前
设计模式有哪几类?
前端·后端·设计模式
你的人类朋友16 小时前
适配器模式:适配就完事了bro!
前端·后端·设计模式
紫荆鱼19 小时前
设计模式-适配器模式(Adapter)
c++·设计模式·适配器模式
政采云技术1 天前
前端设计模式详解
前端·设计模式
崎岖Qiu1 天前
【设计模式笔记07】:迪米特法则
java·笔记·设计模式·迪米特法则
杯莫停丶2 天前
设计模式之:模板模式
开发语言·设计模式