一. 定义与类型
定义:针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。当代码中有大量的if...else...时,可以使用策略模式
类型:行为型。
二. 使用场景
(1) 系统有很多类,而他们的区别仅仅在于他们的行为不同
(2) 一个系统需要动态的几种算法中选择一种
三. 优缺点
优点:
(1) 符合开闭原则
(2) 避免使用多重条件转移语句
(3) 提高算法的保密性和安全性
缺点:
(1) 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
(2) 产生很多策略类
四. 相关设计模式
策略模式和工厂模式
策略模式和状态模式
五. Coding
先引入一个业务场景:假设在618和双十一的时候,各大电商会有各种促销;而促销就是课程的一个行为,但是这种促销行为有多种实现,网站里面的课程促销:
先创建一个促销策略接口:
/*** @program: designModel
* @description: 促销策略接口
*@author: YuKai Fan
* @create: 2019-02-13 16:47
**/
public interfacePromotionStrategy {voiddoPromotion();
}
创建三个实现类分别代表各种策略,实现策略接口,立减策略:
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:48
**/
public class LiJianPromotionStrategy implementsPromotionStrategy {public voiddoPromotion() {
System.out.println("立减促销,课程的价格直接减去配置的价格");
}
}
返现策略:
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:50
**/
public class FanXianPromotionStrategy implementsPromotionStrategy {public voiddoPromotion() {
System.out.println("返现促销,返回的金额存放到网站用户的余额中");
}
}
满减策略:
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:49
**/
public class ManJianPromotionStrategy implementsPromotionStrategy {public voiddoPromotion() {
System.out.println("满减促销,满200减20元");
}
}
策略执行类:
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:51
**/
public classPromotionActivity {privatePromotionStrategy promotionStrategy;publicPromotionActivity(PromotionStrategy promotionStrategy) {this.promotionStrategy =promotionStrategy;
}public voidexecutePromotionStrategy() {
promotionStrategy.doPromotion();
}
}
应用层:
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:52
**/
public classTest {public static voidmain(String[] args) {//在618的时候,使用立减策略
PromotionActivity promotionActivity618 = new PromotionActivity(newLiJianPromotionStrategy());//在双11的时候,使用满减策略
PromotionActivity promotionActivity1111 = new PromotionActivity(newManJianPromotionStrategy());
promotionActivity618.executePromotionStrategy();
promotionActivity1111.executePromotionStrategy();
}
}
结果:
UML类图:
如果要修改业务,只需要新增一个策略类即可,还可以对上面的应用层进行改进
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:52
**/
public classTest {public static voidmain(String[] args) {
PromotionActivity promotionActivity= null;//创建一个promotionKey
String promotionKey = "LIJIAN";if (StringUtils.equals(promotionKey, "LIJIAN")) {
promotionActivity= new PromotionActivity(newLiJianPromotionStrategy());
}else if (StringUtils.equals(promotionKey, "FANXIAN")) {
promotionActivity= new PromotionActivity(newFanXianPromotionStrategy());
}//....
promotionActivity.executePromotionStrategy();
}
结果:
还可以把策略模式和工厂模式结合到一起(为了避免空指针异常,可以创建一个空的促销策略):
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 17:10
**/
public class EmptyPromotionStrategy implementsPromotionStrategy {public voiddoPromotion() {
System.out.println("无促销");
}
}
创建一个促销策略工厂类:
/*** @program: designModel
* @description: 促销策略工厂的实现
*@author: YuKai Fan
* @create: 2019-02-13 17:10
**/
public classPromotionStrategyFactory {private static Map PROMOTION_STRATEGY_MAP = new HashMap();static{
PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN,newLiJianPromotionStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN,newFanXianPromotionStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN,newManJianPromotionStrategy());
}private static final PromotionStrategy NON_PROMOTION = newEmptyPromotionStrategy();privatePromotionStrategyFactory() {
}public staticPromotionStrategy getNonPromotion(String promotionKey) {
PromotionStrategy promotionStrategy=PROMOTION_STRATEGY_MAP.get(promotionKey);return promotionStrategy == null ?NON_PROMOTION : promotionStrategy;
}private interfacePromotionKey{
String LIJIAN= "LIJIAN";
String FANXIAN= "FANXIAN";
String MANJIAN= "MANJIAN";
}
}
应用层:
/*** @program: designModel
* @description:
*@author: YuKai Fan
* @create: 2019-02-13 16:52
**/
public classTest {public static voidmain(String[] args) {/*** 策略模式与工厂模式结合*/String promotionKey= "LIJIAN";
PromotionActivity promotionActivity= newPromotionActivity(PromotionStrategyFactory.getNonPromotion(promotionKey));
promotionActivity.executePromotionStrategy();
}
}
结果:
策略模式一般都不会单独去使用,一般会结合单例,工厂方法,享元模式去使用
六. 源码分析