设计模式之策略模式
策略模式
策略模式(Strategy),就是⼀个问题有多种解决⽅案,选择其中的⼀种使⽤,这种情况下我们使⽤策略模式来实现灵活地选择,也能够⽅便地增加新的解决⽅案。⽐如做数学题,⼀个问题的解法可能有多种;再⽐如商场的打折促销活动,打折⽅案也有很多种,有些商品是不参与折扣活动要按照原价销售,有些商品打8.5折,有些打6折,有些是返现5元等。策略(Strategy)定义所有⽀持算法的公共接⼝。Context使⽤这个接⼝来调⽤某 ConcreteStrategy定义的算法。策略实现(ConcreteStrategy)实现了Strategy 接⼝的具体算法上下⽂(Context)维护⼀个 Strategy 对象的引⽤,⽤⼀个 ConcreteStrategy 对象来装配,可定义⼀个接⼝⽅法让Strategy 访问它的数据。
示例,假如现在有⼀个商场优惠活动,有的商品原价售卖,有的商品打8.5折,有的商品打6折,有的返现5元。
public class BuyGoods { private String goods; private double price; private double finalPrice; private String desc;
public BuyGoods(String goods, double price) { this.goods = goods; this.price = price; }
public double calculate(String discountType) { if ("discount85".equals(discountType)) { finalPrice = price * 0.85; desc = "该商品可享受8.5折优惠"; } else if ("discount6".equals(discountType)) { finalPrice = price * 0.6; desc = "该商品可享受6折优惠"; } else if ("return5".equals(discountType)) { finalPrice = price >= 5 ? price - 5 : 0; desc = "该商品可返现5元"; } else { finalPrice = price; desc = "对不起,该商品不参与优惠活动"; } System.out.println(MessageFormat.format("您购买的商品为:{0},原价为:{1},{2},最终售卖价格为:{3}", goods, price, desc, finalPrice)); return finalPrice; } }
测试
public class Test { public static void main(String[] args) { BuyGoods buyGoods1 = new BuyGoods("Java编程思想", 99.00); buyGoods1.calculate("discount85"); BuyGoods buyGoods2 = new BuyGoods("罗技⿏标", 66 ); buyGoods2.calculate("discount6"); BuyGoods buyGoods3 = new BuyGoods("苹果笔记本", 15000.00); buyGoods3.calculate("return5"); BuyGoods buyGoods4 = new BuyGoods("佳能相机", 1900); buyGoods4.calculate(null); } }
上述代码可以解决问题,但是从代码设计的⻆度还是存在⼀些问题增加或者修改打折⽅案时必须修改 BuyGoods 类源代码,违反了⾯向对象设计的 "开闭原则",代码的灵活性和扩展性较差。打折⽅案代码聚合在⼀起,如果其他项⽬需要重⽤某个打折⽅案的代码,只能复制粘贴对应代码,⽆法以类组件的⽅式进⾏重⽤,代码的复⽤性差。BuyGoods 类的 calculate() ⽅法随着优惠⽅案的增多会⾮常庞⼤,代码中会出现很多if分⽀,可维护性差。此时,我们可以使⽤策略模式对 BuyGoods 类进⾏重构,将打折⽅案逻辑(算法)的定义和使⽤分离。抽象策略类 AbstractDiscount,它是所有具体打折⽅案(算法)的⽗类,定义了⼀个 discount抽象⽅法
public abstract class AbstractDiscount { public double getFinalPrice() { return finalPrice; } public void setFinalPrice(double finalPrice) { this.finalPrice = finalPrice; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } protected double finalPrice; protected String desc; public AbstractDiscount(String desc) { this.desc = desc; } public abstract double discount(double price); }
四种具体策略类,继承⾃抽象策略类 AbstractDiscount,并在 discount ⽅法中实现具体的打折⽅案(算法)
public class Discount85 extends AbstractDiscount { public Discount85() { super("该商品可享受8.5折优惠"); } @Override public double discount(double price) { finalPrice = price * 0.85; return finalPrice; } } public class Discount6 extends AbstractDiscount { public Discount6() { super("该商品可享受6折优惠"); } @Override public double discount(double price) { finalPrice = price * 0.6; return finalPrice; } } public class Return5 extends AbstractDiscount { public Return5() { super("该商品可返现5元"); } @Override public double discount(double price) { this.finalPrice = price >= 5 ? price - 5 : 0; return finalPrice; } } public class NoDiscount extends AbstractDiscount { public NoDiscount() { super("对不起,该商品不参与优惠活动"); } @Override public double discount(double price) { finalPrice = price; return finalPrice; } }
类 BuyGoods,维护了⼀个 AbstractDiscount 引⽤
public class BuyGoods { private String goods; private double price; private AbstractDiscount abstractDiscount; public BuyGoods(String goods, double price, AbstractDiscount abstractDiscount) { this.goods = goods; this.price = price; this.abstractDiscount = abstractDiscount; } public double calculate() { double finalPrice = abstractDiscount.discount(this.price); String desc = abstractDiscount.getDesc(); System.out.println(MessageFormat.format("商品:{0},原价:{1},{2},最终价格为:{3}", goods, price, desc, finalPrice)); return finalPrice; } }
测试
public class Test { public static void main(String[] args) { BuyGoods buyGoods1 = new BuyGoods("Java编程思想", 99.00, new Discount85()); buyGoods1.calculate(); BuyGoods buyGoods2 = new BuyGoods("罗技⿏标", 66, new Discount6()); buyGoods2.calculate(); BuyGoods buyGoods3 = new BuyGoods("苹果笔记本", 15000.00, new Return5()); buyGoods3.calculate(); BuyGoods buyGoods4 = new BuyGoods("佳能相机", 1900, new NoDiscount()); buyGoods4.calculate(); } }
重构后:
增加新的优惠⽅案时只需要继承抽象策略类即可,修改优惠⽅案时不需要修改BuyGoods类源码;代码复⽤也变得简单,直接复⽤某⼀个具体策略类即可;BuyGoods类的calculate变得简洁,没有了原本的if分⽀;
浙公网安备 33010602011771号