对策略模式的理解

目录

一、场景

  • 程序员除了会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;
	...
}
相关推荐
南城花随雪。20 小时前
Spring框架之策略模式 (Strategy Pattern)
java·spring·策略模式
Fre丸子_20 小时前
设计者模式之策略模式
c++·策略模式
超越不平凡20 小时前
Spring Plugin与策略模式:打造动态可扩展的应用
spring·策略模式·spring plugin
G皮T2 天前
【设计模式】行为型模式(二):策略模式、命令模式
java·设计模式·策略模式·命令模式·command·strategy
7年老菜鸡4 天前
策略模式(C++)三分钟读懂
c++·qt·策略模式
也无晴也无风雨5 天前
代码中的设计模式-策略模式
设计模式·bash·策略模式
凉辰5 天前
设计模式 策略模式 场景Vue (技术提升)
vue.js·设计模式·策略模式
菜菜-plus5 天前
java设计模式之策略模式
java·设计模式·策略模式
XYX的Blog6 天前
设计模式09-行为型模式2(状态模式/策略模式/Java)
设计模式·状态模式·策略模式
Slow菜鸟12 天前
Spring 设计模式之策略模式
spring·设计模式·策略模式