【3 分钟上手策略模式:从 if-else 泥潭到代码 “灵活切换” 的逆袭】

一、核心概念

策略模式(Strategy Pattern)是一种行为型设计模式,它的核心思想是将算法(或行为)封装成独立的策略类,使得它们可以互相替换,从而让算法的变化独立于使用算法的客户端。

解决的问题
当一个类中包含多种类似的算法(或行为),且这些算法可能频繁变化时,直接在类中用 if-else 或 switch 判断逻辑会导致代码臃肿、难以维护。策略模式通过将每种算法封装成独立的策略类,消除了条件判断,同时让算法的扩展和替换更灵活。策略模式是一种非常实用的设计模式,它允许你在运行时选择算法的行为。

策略模式包含三个主要角色:

  • 策略接口(Strategy Interface):定义所有具体策略必须实现的公共方法。
  • 具体策略(Concrete Strategies):实现策略接口的具体算法。
  • 上下文(Context):持有一个策略接口的引用,并在运行时调用具体策略的方法。

二、 传统实现方式(使用条件语句)

在不使用策略模式的情况下,通常会将所有折扣逻辑集中在一个类中,通过 if-else 或 switch 语句来判断使用哪种折扣算法。
以下是 Java 代码示例:

class Order {
    private String memberType;  // 会员类型:NORMAL, SILVER, GOLD
    private double amount;      // 订单金额

    public Order(String memberType, double amount) {
        this.memberType = memberType;
        this.amount = amount;
    }

    // 计算最终价格(包含所有折扣逻辑)
    public double calculateFinalPrice() {
        double finalPrice = amount;

        // 根据会员类型应用不同折扣
        if ("SILVER".equals(memberType)) {
            finalPrice = amount * 0.95;  // 银卡会员95折
        } else if ("GOLD".equals(memberType)) {
            finalPrice = amount * 0.9;   // 金卡会员9折
        } 
        // 可以继续添加更多会员类型的折扣逻辑...

        return finalPrice;
    }
}
// 使用示例
public class TraditionalExample {
    public static void main(String[] args) {
        // 创建普通会员订单
        Order normalOrder = new Order("NORMAL", 1000);
        System.out.println("普通会员价格: " + normalOrder.calculateFinalPrice());

        // 创建银卡会员订单
        Order silverOrder = new Order("SILVER", 1000);
        System.out.println("银卡会员价格: " + silverOrder.calculateFinalPrice());

        // 创建金卡会员订单
        Order goldOrder = new Order("GOLD", 1000);
        System.out.println("金卡会员价格: " + goldOrder.calculateFinalPrice());
    }
}

传统实现的问题:

  1. 代码臃肿:所有折扣逻辑集中在一个方法中,随着会员类型增加,calculateFinalPrice() 会变得非常庞大。
  2. 违反开闭原则:新增会员类型(如铂金会员:“PLATINUM”)时,必须修改 Order类 的源代码,增加新的 else if 分支。
  3. 缺乏复用性:如果其他地方需要使用相同的折扣算法,无法直接复用,只能复制粘贴代码。 难以维护:大量条件语句使代码可读性降低,维护成本增加。

三、Java 实现策略模式

下面是一个使用 Java 实现的策略模式示例,以计算不同会员等级的折扣为例:

1.策略接口

// 策略接口:定义计算折扣的方法
public interface DiscountStrategy {
    double applyDiscount(double amount);
}

2.具体策略 (实现类)

// 具体策略:普通会员(无折扣)
public class NormalMemberStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double amount) {
        return amount; // 无折扣
    }
}

// 具体策略:银卡会员(95折)
public class SilverMemberStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double amount) {
        return amount * 0.95; // 95折
    }
}

// 具体策略:金卡会员(9折)
public class GoldMemberStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double amount) {
        return amount * 0.9; // 9折
    }
}

3.上下文

// 上下文:订单类
public class Order {
    private DiscountStrategy discountStrategy;

    // 通过构造函数注入策略
    public Order(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    // 允许在运行时更改策略
    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    // 应用折扣计算最终价格
    public double calculateFinalPrice(double amount) {
        return discountStrategy.applyDiscount(amount);
    }
}

4.使用示例

// 使用示例
public class StrategyPatternExample {
    public static void main(String[] args) {
        // 创建一个普通会员订单
        Order normalOrder = new Order(new NormalMemberStrategy());
        System.out.println("普通会员最终价格: " + normalOrder.calculateFinalPrice(1000));

        // 创建一个银卡会员订单
        Order silverOrder = new Order(new SilverMemberStrategy());
        System.out.println("银卡会员最终价格: " + silverOrder.calculateFinalPrice(1000));

        // 创建一个金卡会员订单
        Order goldOrder = new Order(new GoldMemberStrategy());
        System.out.println("金卡会员最终价格: " + goldOrder.calculateFinalPrice(1000));

        // 动态更改策略:普通会员升级为银卡会员
        normalOrder.setDiscountStrategy(new SilverMemberStrategy());
        System.out.println("升级后普通会员最终价格: " + normalOrder.calculateFinalPrice(1000));
    }
}

四、Java 8+ 的改进

在 Java 8 及以后,可以使用函数式接口和 Lambda 表达式简化策略模式的实现:针对一些简单逻辑的实现,无需为每个策略创建具体的实现类,直接用 Lambda 表达式表示策略逻辑。

1.策略接口

// 使用函数式接口替代传统策略接口
@FunctionalInterface
public interface DiscountStrategy {
    double applyDiscount(double amount);
}

函数式接口是指只包含一个抽象方法的接口(可以包含多个默认方法或静态方法,但抽象方法必须仅有一个)。这个接口可以用于Lambda 表达式方法引用(函数式接口是 Lambda 表达式的基础)。

抽象策略的抽象方法可以有多个,此例子针对单个抽象方法而言。

2.上下文

// 上下文类保持不变
public class Order {
    private DiscountStrategy discountStrategy;

    public Order(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double calculateFinalPrice(double amount) {
        return discountStrategy.applyDiscount(amount);
    }
}

3.使用示例

// 使用示例
public class StrategyPatternWithLambda {
    public static void main(String[] args) {
        // 使用Lambda表达式创建具体策略
        DiscountStrategy normalStrategy = amount -> amount; // 无折扣
        DiscountStrategy silverStrategy = amount -> amount * 0.95; // 95折
        DiscountStrategy goldStrategy = amount -> amount * 0.9; // 9折

        // 创建订单并应用不同策略
        Order order = new Order(normalStrategy);
        System.out.println("普通会员价格: " + order.calculateFinalPrice(1000));

        order.setDiscountStrategy(silverStrategy);
        System.out.println("银卡会员价格: " + order.calculateFinalPrice(1000));

        order.setDiscountStrategy(goldStrategy);
        System.out.println("金卡会员价格: " + order.calculateFinalPrice(1000));
    }
}

五、 策略模式的优势

  • 符合开闭原则:新增策略时无需修改现有代码,只需实现策略接口。
  • 避免条件语句:替代复杂的 if-else 或 switch 逻辑。
  • 运行时动态切换:可以在运行时根据需要更换策略。
  • 代码复用:策略类可以在多个上下文中复用。
对比点传统实现(条件语句)策略模式
代码结构折扣逻辑集中在一个类中,通过条件语句分支折扣逻辑分散到独立的策略类中
扩展性新增策略需修改原有代码(违反开闭原则)新增策略只需添加新类(符合开闭原则)
复用性逻辑难以复用策略类可在多个地方复用
复杂度随着策略增加,代码复杂度呈指数级增长策略类独立,整体复杂度低
运行时切换难以在运行时动态切换策略可以通过setStrategy()方法动态切换

六、应用场景

  • 支付方式选择(信用卡、支付宝、微信支付等)。
  • 针对不同厂家的数据对接。
  • 排序算法选择(冒泡排序、快速排序、归并排序等)。
  • 压缩算法选择(ZIP、GZIP、BZIP2 等)。
  • 会员等级折扣计算(如示例所示)。

One More

在策略模式中,具体策略类可通过封装私有方法实现差异化逻辑,其核心优势在于使用者只需依赖抽象策略接口,无需关心具体实现细节。这些私有方法被隔离在各自类中,不会对接口调用产生影响;而传统设计往往将多种策略的实现逻辑混杂在一起,导致代码耦合度高、可维护性差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值