对策略模式的理解

目录

一、场景

  • 程序员除了会ctrl+ c + ctrl + v之外,最擅长的莫过于写if...else...了,哈哈:)
  • 有些场景下,我们可以预料到,会写非常多的if...else if...else if ... else if ...。这时候,可以使用策略模式。

1、题目描述 【来源

小明家的超市推出了不同的购物优惠策略,你可以根据自己的需求选择不同的优惠方式。其中,有两种主要的优惠策略:

  1. 九折优惠策略:原价的90%。
  2. 满减优惠策略:购物满一定金额时,可以享受相应的减免优惠。
    具体的满减规则如下:

满100元减5元

满150元减15元

满200元减25元

满300元减40元
请你设计一个购物优惠系统,用户输入商品的原价和选择的优惠策略编号,系统输出计算后的价格。

2、输入描述

输入的第一行是一个整数 N(1 ≤ N ≤ 20),表示需要计算优惠的次数。

接下来的 N 行,每行输入两个整数,第一个整数M( 0 < M < 400) 表示商品的价格, 第二个整数表示优惠策略,1表示九折优惠策略,2表示满减优惠策略

3、输出描述

每行输出一个数字,表示优惠后商品的价格

4、输入示例

4

100 1

200 2

300 1

300 2

5、输出示例

90

175

270

260

二、不使用策略模式

  • 代码:
java 复制代码
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        for (int i = 0; i < n; i++) {
            int price = scanner.nextInt();
            int strategyNum = scanner.nextInt();

            if (strategyNum == 1) {
                System.out.println((int) (price * 0.9));
            } else if (strategyNum == 2) {
                if (price < 100) {
                    System.out.println(price);
                } else if (price < 150) {
                    // 满100元减5元
                    System.out.println(price - 5);
                } else if (price < 200) {
                    // 满150元减15元
                    System.out.println(price - 15);
                } else if (price < 300) {
                    // 满200元减25元
                    System.out.println(price - 25);
                } else {
                    // 满300元减40元
                    System.out.println(price - 40);
                }

            } else {
                throw new RuntimeException("Invalid strategy number");
            }
        }

    }
}
  • 问题:
    • 可以预见的是,随着发展,优惠策略肯定不止一种。
    • 因此,可以用策略模式优化代码。

三、使用策略模式

1、不优雅的实现

  • 策略
java 复制代码
public interface Strategy<T> {
    void execute(T data);
}

@AllArgsConstructor
public class DiscountStrategy implements Strategy<Integer> {
    private Double discount;

    @Override
    public void execute(Integer data) {
        System.out.println((int) (data * discount));
    }
}

public class FullMinusStrategy implements Strategy<Integer> {
    @Override
    public void execute(Integer price) {
        if (price < 100) {
            System.out.println(price);
        } else if (price < 150) {
            // 满100元减5元
            System.out.println(price - 5);
        } else if (price < 200) {
            // 满150元减15元
            System.out.println(price - 15);
        } else if (price < 300) {
            // 满200元减25元
            System.out.println(price - 25);
        } else {
            // 满300元减40元
            System.out.println(price - 40);
        }
    }
}
  • 客户端
java 复制代码
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        Strategy strategy = null;
        for (int i = 0; i < n; i++) {
            int price = scanner.nextInt();
            int strategyNum = scanner.nextInt();

            switch (strategyNum) {
                case 1:
                    strategy = new DiscountStrategy(0.9D);
                    break;
                case 2:
                    strategy = new FullMinusStrategy();
                    break;
                default:
                    new RuntimeException("Strategy not found");
            }

            strategy.execute(price);
        }
    }
}
  • 啊这,这不还是写if...esle吗?(switch只是对if...else的美化而已)
  • 我们其实已经知道<1, DiscountStrategy>, <2, FullMinusStrategy>,因此,可以提前建立联系。

2、策略模式 + 简单工厂模式

2.1 代码

  • 策略和上面一样
java 复制代码
public interface Strategy<T> {
    ...
}

@AllArgsConstructor
public class DiscountStrategy implements Strategy<Integer> {
    ...
}

public class FullMinusStrategy implements Strategy<Integer> {
    ...
}
  • 对策略的封装:
java 复制代码
public class StrategyManager {
    private static final Map<Integer, Strategy> strategies = new HashMap<>();

    public StrategyManager() {
        strategies.put(1, new DiscountStrategy(0.9D));
        strategies.put(2, new FullMinusStrategy());
    }

    public void execute(Integer strategyNum, Integer data) {
        Strategy strategy = strategies.get(strategyNum);
        if (strategy == null) {
            throw new RuntimeException("Strategy not found");
        }

        strategy.execute(data);
    }
}
  • 客户端:
java 复制代码
public class Application {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();

        StrategyManager strategyManager = new StrategyManager();
        for (int i = 0; i < n; i++) {
            int price = scanner.nextInt();
            int strategyNum = scanner.nextInt();

            strategyManager.execute(strategyNum, price);
        }
    }
}

2.2 优点

  • 即使再增加一种策略,也不用修改客户端的代码。
  • 然而,没有Spring的辅助下,需要自己构建Map<Integer, Strategy> strategies,这使得增加一种策略时,还得修改StrategyManager类。

2.3 另一种实现方式

  • 策略:
java 复制代码
public interface Strategy<T, R> {
    boolean match(R matchContext);
    void execute(T data);
}

@AllArgsConstructor
public class DiscountStrategy implements Strategy<Integer, Integer> {
    private Double discount;

    @Override
    public boolean match(Integer matchContext) {
        return matchContext == 1;
    }

    @Override
    public void execute(Integer data) {
        System.out.println((int) (data * discount));
    }
}

public class FullMinusStrategy implements Strategy<Integer, Integer> {
    @Override
    public boolean match(Integer matchContext) {
        return matchContext == 2;
    }

    @Override
    public void execute(Integer price) {
        if (price < 100) {
            System.out.println(price);
        } else if (price < 150) {
            // 满100元减5元
            System.out.println(price - 5);
        } else if (price < 200) {
            // 满150元减15元
            System.out.println(price - 15);
        } else if (price < 300) {
            // 满200元减25元
            System.out.println(price - 25);
        } else {
            // 满300元减40元
            System.out.println(price - 40);
        }
    }
}
  • 对策略的封装:
java 复制代码
public class StrategyManager {
//    private static final Map<Integer, Strategy> strategies = new HashMap<>();
    private static final List<Strategy> strategies = new ArrayList<>();

    public StrategyManager() {
        strategies.add(new DiscountStrategy(0.9D));
        strategies.add(new FullMinusStrategy());
    }

    public void execute(Integer strategyNum, Integer data) {
        Strategy strategy = strategies.stream()
                .filter(s -> s.match(strategyNum))
                .findFirst()
                .orElse(null);
        if (strategy == null) {
            throw new RuntimeException("Strategy not found");
        }

        strategy.execute(data);
    }
}
  • 客户端和上面一样。

个人觉得这种方式更灵活。

四、个人思考

  • 当遇到写非常多的if...else if...else if ... else if ...时,说明<规则,处理>是确定的。
  • 那么完全可以抽象为:
java 复制代码
public interface Strategy<T, R> {
    boolean match(R matchContext); // 匹配规则
    void execute(T data); // 处理数据
}

各种具体的xxxStrategy
java 复制代码
@Component
public class StrategyManager {
    @Autowired
    private List<Strategy> strategies;

    public void execute(Integer strategyNum, Integer data) {
        Strategy strategy = strategies.stream()
                .filter(s -> s.match(strategyNum))
                .findFirst()
                .orElse(null);
        if (strategy == null) {
            throw new RuntimeException("Strategy not found");
        }

        strategy.execute(data);
    }
}
  • 小插曲,后续会写文章解释。
java 复制代码
@Component
public class StrategyManager {
	// 字段注入,不支持静态变量。
    @Autowired
    private static List<Strategy> strategies;
	...
}
相关推荐
熊出没14 小时前
解锁策略模式:Java 实战与应用全景解析
策略模式
黑不溜秋的1 天前
C++ 设计模式 - 策略模式
c++·设计模式·策略模式
ox00803 天前
C++ 设计模式-策略模式
c++·设计模式·策略模式
Hadesls5 天前
MacOS 15.3 卸载系统内置软件
macos·策略模式
Tang Paofan10 天前
【C++】策略模式
开发语言·c++·策略模式
bug的abc12 天前
策略模式-小结
策略模式
谢道韫66612 天前
从0到1:ArkTS实现鸿蒙策略模式全解析
华为·harmonyos·策略模式
geekmice12 天前
问题:通过策略模式+工厂模式+模板方法模式实现ifelse优化
策略模式·模板方法模式
添砖Java中12 天前
深度解析策略模式:从理论到企业级实战应用
spring boot·spring·spring cloud·设计模式·maven·策略模式
weixin_4383354013 天前
设计模式之策略模式
设计模式·策略模式