自学内容网 自学内容网

告别条件判断:策略模式让代码更优雅

告别条件判断:策略模式让代码更优雅

🎯 策略模式(Strategy Pattern)简介

策略模式 是一种行为型设计模式,定义了一系列算法或行为,并将它们封装起来,使它们可以互换使用。通过将不同的算法封装在独立的策略类中,策略模式使得算法可以独立于使用它的客户端进行变化。

核心思想

策略模式通过封装变化的部分,允许程序在运行时动态选择不同的策略(算法)进行处理,避免了在客户端代码中使用条件语句来选择算法,从而提高了系统的灵活性。

策略模式的 UML 类图

在这里插入图片描述

角色说明

  1. Strategy(策略接口)
    • 定义了一个共同的接口,用于封装算法或行为。所有具体的策略类都会实现这个接口,并定义各自的具体算法。
  2. ConcreteStrategy(具体策略类)
    • 每个具体的策略类实现了 Strategy 接口,定义了一个具体的算法或行为。
  3. Context(上下文类)
    • 上下文类持有一个策略对象,并调用该策略的算法。在运行时,上下文可以更改其使用的策略,以便动态地选择不同的算法。

生动案例:电商平台的促销活动策略

场景说明

假设我们有一个电商平台,在不同的时间段内会有不同的促销活动,比如:

  • 打折促销:给顾客的商品价格打折。
  • 满减促销:当顾客消费满一定金额时,给予一定的减免。

我们希望能灵活地切换不同的促销策略,而不必每次都修改核心代码。可以使用策略模式,根据不同的促销活动动态选择促销算法。

角色映射

  1. Strategy:促销策略接口,定义通用的促销算法。
  2. ConcreteStrategy:具体的促销策略,例如打折、满减等。
  3. Context:购物车,负责根据不同的促销策略计算最终价格。

代码实现:电商促销活动策略

Step 1: 定义策略接口

PromotionStrategy 接口定义了一个通用的促销方法。

// 策略接口:促销策略
public interface PromotionStrategy {
    double applyDiscount(double price);
}

Step 2: 实现具体的策略类

具体策略类实现 PromotionStrategy 接口,根据不同的促销活动,返回相应的折扣或优惠价格。

打折策略

// 具体策略类:打折促销
public class PercentageDiscountStrategy implements PromotionStrategy {
    private double discountPercentage;

    public PercentageDiscountStrategy(double discountPercentage) {
        this.discountPercentage = discountPercentage;
    }

    @Override
    public double applyDiscount(double price) {
        return price * (1 - discountPercentage / 100);
    }
}

满减策略

// 具体策略类:满减促销
public class ThresholdDiscountStrategy implements PromotionStrategy {
    private double threshold;
    private double discount;

    public ThresholdDiscountStrategy(double threshold, double discount) {
        this.threshold = threshold;
        this.discount = discount;
    }

    @Override
    public double applyDiscount(double price) {
        if (price >= threshold) {
            return price - discount;
        }
        return price;
    }
}

Step 3: 定义上下文类

ShoppingCart 类作为上下文,它通过持有一个 PromotionStrategy 来动态选择促销策略。

// 上下文类:购物车
public class ShoppingCart {
    private PromotionStrategy strategy;

    public void setPromotionStrategy(PromotionStrategy strategy) {
        this.strategy = strategy;
    }

    public double calculateTotalPrice(double price) {
        if (strategy != null) {
            return strategy.applyDiscount(price);
        }
        return price;
    }
}

Step 4: 测试策略模式

public class StrategyPatternDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        // 设置打折促销策略
        cart.setPromotionStrategy(new PercentageDiscountStrategy(10)); // 10% 打折
        double discountedPrice = cart.calculateTotalPrice(200);
        System.out.println("Discounted price with 10% off: " + discountedPrice);

        // 设置满减促销策略
        cart.setPromotionStrategy(new ThresholdDiscountStrategy(300, 50)); // 满300减50
        double discountedPrice2 = cart.calculateTotalPrice(350);
        System.out.println("Discounted price with threshold discount: " + discountedPrice2);
    }
}

输出结果

Discounted price with 10% off: 180.0
Discounted price with threshold discount: 300.0

策略模式的优缺点

优点

  1. 开闭原则
    • 策略模式使得算法或行为的扩展变得非常容易。你可以通过添加新的策略类来扩展新的行为,而不需要修改已有的代码。
  2. 消除条件判断
    • 通过策略模式,可以避免在客户端代码中使用大量的 if-elseswitch 语句来选择算法,从而使代码更加清晰。
  3. 提高灵活性
    • 在运行时可以根据具体情况动态选择不同的策略,使得系统在不同场景下表现出不同的行为。

缺点

  1. 增加了类的数量
    • 每一个具体的策略都需要实现 Strategy 接口,这会导致类的数量增多,增加了系统的复杂度。
  2. 客户端需要了解策略
    • 客户端必须知道所有的策略类,并且要根据具体情况来选择合适的策略,可能会增加使用的复杂度。

策略模式的应用场景

  1. 算法或行为多变的场景
    • 当一个类中存在多个算法,且这些算法是可以互换的,可以使用策略模式来动态选择算法。
  2. 避免使用条件判断的场景
    • 在需要根据不同条件选择不同的行为时,策略模式可以避免 if-elseswitch 语句的使用。
  3. 需要动态改变行为的场景
    • 当程序需要在运行时根据不同的情况选择不同的行为时,策略模式能够提供灵活的解决方案。

策略思想在优秀框架中的应用

JDK 中的 Comparator 接口

Comparator 是 Java 集合框架中策略模式的一个经典应用。它允许我们定义对象排序的策略,并可以在不同场景中使用不同的比较策略。

如何应用策略模式

  • Comparator 接口定义了比较两个对象的方法 compare()
  • 我们可以创建多个 Comparator 实现类,每个类对应不同的排序策略(如按名称、年龄排序等)。
  • Collections.sort() 方法可以动态地使用不同的 Comparator 来实现不同的排序逻辑。

示例代码

import java.util.*;

public class ComparatorStrategyExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        // 按照姓名排序
        Collections.sort(people, new NameComparator());
        System.out.println("Sorted by name: " + people);

        // 按照年龄排序
        Collections.sort(people, new AgeComparator());
        System.out.println("Sorted by age: " + people);
    }
}

class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}

// 按照姓名排序的策略
class NameComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p1.name.compareTo(p2.name);
    }
}

// 按照年龄排序的策略
class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return Integer.compare(p1.age, p2.age);
    }
}

Comparator 是策略模式的典型实现,不同的 Comparator 类实现了不同的排序策略(按姓名或按年龄排序)。Collections.sort() 可以根据传入的 Comparator 动态选择排序策略。

Java 的 ThreadPoolExecutor

Java 的并发包中,ThreadPoolExecutor 也是策略模式的一个重要应用。ThreadPoolExecutor 允许你为线程池配置不同的任务提交、拒绝和管理策略。

如何应用策略模式

  • RejectedExecutionHandler 接口定义了任务提交失败时的策略。
  • 我们可以通过实现 RejectedExecutionHandler 接口来创建不同的任务拒绝策略(如丢弃任务、抛异常等)。
  • ThreadPoolExecutor 动态使用这些策略处理任务提交失败的情况
import java.util.concurrent.*;

public class ThreadPoolStrategyExample {
    public static void main(String[] args) {
        // 创建一个线程池,并设置拒绝策略
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, 2, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(2),
                new RejectedTaskHandler());  // 使用自定义拒绝策略

        // 提交超出容量的任务
        for (int i = 0; i < 5; i++) {
            executor.submit(new Task("Task " + i));
        }

        executor.shutdown();
    }
}

// 自定义任务
class Task implements Runnable {
    private String name;

    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("Executing " + name);
    }
}

// 自定义拒绝策略
class RejectedTaskHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("Task rejected: " + ((Task) r).name);
    }
}

Spring 中的 @Qualifier@Primary(依赖注入策略)

Spring 框架中,@Qualifier@Primary 注解用于指定依赖注入时的策略选择。这也可以看作是一种策略模式的应用,允许 Spring 选择适合的实现进行注入。

如何应用策略模式

  • 当多个实现类实现同一个接口时,Spring 允许通过 @Qualifier@Primary 来指定注入的策略,即选择注入哪个具体的实现类。
  • 这种注解配置相当于动态选择了一个依赖注入策略。

示例代码

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Primary;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

// 通用接口
interface PaymentService {
    void pay();
}

// 具体策略类1:支付宝支付
@Component
@Qualifier("alipay")
class AlipayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("Paying with Alipay.");
    }
}

// 具体策略类2:微信支付
@Component
@Primary  // 这个是默认注入策略
class WechatPayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("Paying with Wechat Pay.");
    }
}

// 上下文:支付服务使用
@Component
class PaymentProcessor {
    private final PaymentService paymentService;

    public PaymentProcessor(@Qualifier("alipay") PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void processPayment() {
        paymentService.pay();
    }
}

// Spring配置与测试
@Component
public class StrategySpringDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(StrategySpringDemo.class);
        PaymentProcessor processor = context.getBean(PaymentProcessor.class);
        processor.processPayment();  // 使用支付宝策略进行支付
    }
}

输出结果

Paying with Alipay.

PaymentService 是策略接口,AlipayServiceWechatPayService 是具体的策略实现。通过 @Qualifier 注解,Spring 可以动态选择不同的策略进行依赖注入,达到了策略模式的效果。

总结

策略模式 通过将算法或行为抽象为一系列独立的策略类,使得算法可以在客户端代码之外进行动态选择和替换,极大地提高了系统的灵活性和可扩展性。在电商促销活动的案例中,我们通过策略模式展示了如何灵活地切换促销算法,减少代码中的条件判断,使得不同的促销方案可以动态应用。

策略模式非常适合那些算法或行为经常变化的系统,通过将变化的部分封装起来,增强了系统的扩展性和维护性。


原文地址:https://blog.csdn.net/qq_44732500/article/details/142439019

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!