设计模式(java实现)_策略模式(Strategy)
策略模式是一种对象行为型模式。一般对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一个问题,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。
本质: 分离算法,选择实现
–以下摘自 http://www.runoob.com
意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
关键代码:实现同一个接口。
应用实例: 1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。 2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。 3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
–摘要结束
下面是我写的策略模式的场景应用,场景为用户氪金。根据用户不同,需要采取的算法不同。
如果是普通的实现,即if..else实现 :
package com.skypyb.strategy; /** * 实现起来比较容易,但是代码过于丑陋 * 如果算法特别复杂并且类型特别多则修改麻烦 * 不符合开闭原则 * * @author pyb www.yibobo.top * www.skypyb.com * @time 2018-11-03 */ public class TestOne { public double recharge(String type, double price) { if ("白嫖用户".equals(type)) { System.out.println("白嫖用户充钱得10倍钻"); return price * 10; } else if ("会员".equals(type)) { System.out.println("高贵的会员充钱得12倍钻"); return price * 12; } else if ("黄金会员".equals(type)) { System.out.println("高贵的黄金会员充钱得13倍钻"); return price * 13; } return 0; } }
该种实现应该是一般人第一时间思考到的方式吧。
但是在业务巨复杂算法各种诡异的实际生产场景中,这种类似的需求要是用if..else实现的话,那画面真是太美妙了。
这个时候用策略模式重构一下。
策略接口:
package com.skypyb.strategy.strategy; /** * vip氪金得钻的算法策略接口 */ public interface VipStrategy { /** * 实现类实现该方法以执行不同的算法 */ int recharge(int price); }
具体的几个策略类:
package com.skypyb.strategy.strategy; public class NormalStrategy implements VipStrategy { @Override public int recharge(int price) { System.out.println("白嫖用户充钱得10倍钻"); return price * 10; } }
package com.skypyb.strategy.strategy; public class NormalVipStrategy implements VipStrategy { @Override public int recharge(int price) { System.out.println("高贵的会员充钱得12倍钻"); return price*12; } }
package com.skypyb.strategy.strategy; public class GoldenVipStrategy implements VipStrategy { @Override public int recharge(int price) { System.out.println("高贵的黄金会员充钱得13倍钻"); return price*13; } }
重点,管理策略的上下文对象,一般调用者会根据该对象来执行不同的策略,而执行不同的算法。
package com.skypyb.strategy; import com.skypyb.strategy.strategy.VipStrategy; /** * 上下文对象,用于管理算法 * 负责和具体的策略类交互 * 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化 * @author pyb www.yibobo.top www.skypyb.com */ public class VipContext { private VipStrategy vipStrategy; //构造器注入 public VipContext(VipStrategy vipStrategy) { this.vipStrategy = vipStrategy; } //set注入 public void setVipStrategy(VipStrategy vipStrategy) { this.vipStrategy = vipStrategy; } //氪金的方法 public void getDiamond(int price){ System.out.println(new StringBuffer("您充钱") .append(price) .append("元") .append(",共获得:") .append(vipStrategy.recharge(price)) .append("钻,下次再来氪哦") ); } }
跟上边简单实现的的if..else不同,调用者使用策略模式的方法:
package com.skypyb.strategy; import com.skypyb.strategy.strategy.GoldenVipStrategy; import com.skypyb.strategy.strategy.NormalStrategy; import com.skypyb.strategy.strategy.VipStrategy; /** * 我这实现的策略模式中业务只是最简化的,此时可能还不如 if..else * 毕竟创建了这么多类,相比起 if..else 来说难以管理 * * 但是在实际生产中一个策略可能就会有好几百行代码,这个时候用此模式就会比较舒服 * 根据需求来确定到底执行哪个策略。、还可以和 factory 模式结合起来一起使用 * * */ public class TestStrategy { public static void main(String[] args) { VipStrategy vs1 = new NormalStrategy();//选择需要的策略类 VipContext context = new VipContext(vs1);//实例化上下文对象 context.getDiamond(648);//氪金 System.out.println(); context.setVipStrategy(new GoldenVipStrategy()); context.getDiamond(648); } }
执行后输出语句为:
白嫖用户充钱得10倍钻
您充钱648元,共获得:6480钻,下次再来氪哦
高贵的黄金会员充钱得13倍钻
您充钱648元,共获得:8424钻,下次再来氪哦
成功执行了不同的策略~ 并且代码优雅,可拓展性较强,可以说是很灵性了。
另外:
关于策略模式(strategy)与工厂模式(factory),两者确实比较相似,以至于我刚接触时感到很疑惑,在经过一番资料的查找后终于渐渐明了…其实还真差不多。你用其中一个能完成的功能用另一个也能完成的有模有样的。两者合二为一,那更是牛B,可以在Context上下文对象中使用factory来实例化strategy对象。这样调用者只需要和一个类进行交互即可实现选择不同策略的功能。
分类举例的话:
- 工厂模式是对象创建型模式,专门用于创建对象的,他根据需求创建出不同的实例,将对象的创建和调用者进行了解耦,解决了资源的统一分发。
- 策略模式是对象行为型模式,作用是让一个对象在许多行为中选择一种行为执行,他将策略的变化和使用策略的对象进行了解耦
简单来说工厂模式封装对象,实例化对象后调用的时候要知道具体的方法,策略模式封闭的是行为,调用的时候必须先制定实例化具体的类,再调用抽象的方法。