告别条件判断:策略模式让代码更优雅
告别条件判断:策略模式让代码更优雅
🎯 策略模式(Strategy Pattern)简介
策略模式 是一种行为型设计模式,定义了一系列算法或行为,并将它们封装起来,使它们可以互换使用。通过将不同的算法封装在独立的策略类中,策略模式使得算法可以独立于使用它的客户端进行变化。
核心思想:
策略模式通过封装变化的部分,允许程序在运行时动态选择不同的策略(算法)进行处理,避免了在客户端代码中使用条件语句来选择算法,从而提高了系统的灵活性。
策略模式的 UML 类图
角色说明:
- Strategy(策略接口):
- 定义了一个共同的接口,用于封装算法或行为。所有具体的策略类都会实现这个接口,并定义各自的具体算法。
- ConcreteStrategy(具体策略类):
- 每个具体的策略类实现了
Strategy
接口,定义了一个具体的算法或行为。
- 每个具体的策略类实现了
- Context(上下文类):
- 上下文类持有一个策略对象,并调用该策略的算法。在运行时,上下文可以更改其使用的策略,以便动态地选择不同的算法。
生动案例:电商平台的促销活动策略
场景说明:
假设我们有一个电商平台,在不同的时间段内会有不同的促销活动,比如:
- 打折促销:给顾客的商品价格打折。
- 满减促销:当顾客消费满一定金额时,给予一定的减免。
我们希望能灵活地切换不同的促销策略,而不必每次都修改核心代码。可以使用策略模式,根据不同的促销活动动态选择促销算法。
角色映射:
- Strategy:促销策略接口,定义通用的促销算法。
- ConcreteStrategy:具体的促销策略,例如打折、满减等。
- 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
策略模式的优缺点
优点:
- 开闭原则:
- 策略模式使得算法或行为的扩展变得非常容易。你可以通过添加新的策略类来扩展新的行为,而不需要修改已有的代码。
- 消除条件判断:
- 通过策略模式,可以避免在客户端代码中使用大量的
if-else
或switch
语句来选择算法,从而使代码更加清晰。
- 通过策略模式,可以避免在客户端代码中使用大量的
- 提高灵活性:
- 在运行时可以根据具体情况动态选择不同的策略,使得系统在不同场景下表现出不同的行为。
缺点:
- 增加了类的数量:
- 每一个具体的策略都需要实现
Strategy
接口,这会导致类的数量增多,增加了系统的复杂度。
- 每一个具体的策略都需要实现
- 客户端需要了解策略:
- 客户端必须知道所有的策略类,并且要根据具体情况来选择合适的策略,可能会增加使用的复杂度。
策略模式的应用场景
- 算法或行为多变的场景:
- 当一个类中存在多个算法,且这些算法是可以互换的,可以使用策略模式来动态选择算法。
- 避免使用条件判断的场景:
- 在需要根据不同条件选择不同的行为时,策略模式可以避免
if-else
或switch
语句的使用。
- 在需要根据不同条件选择不同的行为时,策略模式可以避免
- 需要动态改变行为的场景:
- 当程序需要在运行时根据不同的情况选择不同的行为时,策略模式能够提供灵活的解决方案。
策略思想在优秀框架中的应用
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
是策略接口,AlipayService
和 WechatPayService
是具体的策略实现。通过 @Qualifier
注解,Spring 可以动态选择不同的策略进行依赖注入,达到了策略模式的效果。
总结
策略模式 通过将算法或行为抽象为一系列独立的策略类,使得算法可以在客户端代码之外进行动态选择和替换,极大地提高了系统的灵活性和可扩展性。在电商促销活动的案例中,我们通过策略模式展示了如何灵活地切换促销算法,减少代码中的条件判断,使得不同的促销方案可以动态应用。
策略模式非常适合那些算法或行为经常变化的系统,通过将变化的部分封装起来,增强了系统的扩展性和维护性。
原文地址:https://blog.csdn.net/qq_44732500/article/details/142439019
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!