先给出一个情景:编写一个商店收银软件,根据单价和数量计算价格
我们要考虑的
- 在上面所述的情景中,可能出现商品打折情况
- 可能出现满减等新情况
使用简单工厂实现
此处仅给出类图,工厂模式详解见
https://www.xuyuyan.cn/2020/04/23/简单工厂模式
此处使用简单工厂模式存在明显缺陷:
商场会经常性地更改打折额度,每次维护或扩展新的收费方式都要改动工厂
策略模式UML图
策略模式代码实现(Java)
策略接口
1 2 3 4
| public interface PriceStrategy { public abstract double getPrice(int num, double price); }
|
策略方法
1 2 3 4 5 6
| public class ConcretePriceStrategyA implements PriceStrategy { @Override public double getPrice(int num, double price) { return num * price * 0.8; } }
|
1 2 3 4 5 6
| public class ConcretePriceStrategyB implements PriceStrategy { @Override public double getPrice(int num, double price) { return num * price; } }
|
上下文
1 2 3 4 5 6 7 8 9
| public class Context { PriceStrategy priceStrategy; public Context(PriceStrategy priceStrategy) { this.priceStrategy = priceStrategy; } public double ContextInterface(int num, double price) { return priceStrategy.getPrice(num, price); } }
|
客户端
1 2 3 4 5
| public static void main(String[] args) { Context context = new Context(new ConcretePriceStrategyA()); double price = context.ContextInterface(2, 9.9); }
|
通过以上代码可以发现若是算法较多时,客户端将会存在较复杂的swtich语句,所以通常在算法较多时将策略模式和简单工厂模式结合。
策略模式+简单工厂模式
策略接口和策略类不变
上下文工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class ContextFactory { PriceStrategy priceStrategy = null; public ContextFactory(String type) { switch (type) { case "正常收费" : { priceStrategy = new ConcretePriceStrategyB(); break; } case "8折" : { priceStrategy = new ConcretePriceStrategyA(); } } } public double ContextInterface(int num, double price) { return priceStrategy.getPrice(num, price); } }
|
客户端
1 2 3 4 5
| public static void main(String[] args) { ContextFactory contextFactory = new ContextFactory("正常收费"); double price = contextFactory.ContextInterface(2, 9.9); }
|
策略模式的优势
- 减少耦合:以相同的方式j调用所有算法,减少了算法类和使用算法类张子健的耦合
- 可重用:Strategy类层次为Conext定义了可重用的d算法,继承有助于析取公共功能
- 简化单元测试:每个算法都有独立的类,可以单独测试
策略模式的缺点
- 即使和工厂模式结合后仍存在工厂模式的缺点:工厂类的变动频率过高
本文部分内容改编于程杰老师的《大话设计模式》