背景
在做支付宝业务时,接到一个对之前某一模块改造的需求,因之前是某一小哥写的代码,使用if判断比较多,所以想着可以对其进行优化,设计了一个策略模式。
策略模式简介
策略模式呢,是一种行为型模式,它主要是将对象和行为分开,将行为定义为一个行为接口和对某一具体行为的实现。策略模式最大的特点呢,是行为的变化,行为之间可以互相替换。其实上边提到的if判断就可以作为一种策略模式来实现。这种模式使得算法可以根据使用的用户而变化。
模式结构角色
抽象策略类(abstractStrategyInterface):策略是一个接口,该接口定义了 若干个算法,也就是定义了无数个抽象方法。
上下文(Context):
- 上下文是依赖于接口的类,也就是上下文包含用策略(接口)声明的变量。
- 上下文提供一个方法,该方法依托策略变量调用具体策略所实现的策略接口中的方法。(实现接口的类重写策略(接口)中的方法,来完成具体功能)
具体策略类(实现类)(ConcreteStrategyImpl):具体策略是实现策略接口的类,具体策略实现策略接口所定义的抽象方法。
案例
一个简单的例子,对健身房办卡推广的一个系统。对于办理周卡的用户进行5%的折扣,对办理月卡的用户进行10%的折扣,对办理季卡的用户进行15%的折扣,对办理年卡的用户进行20%的折扣。
传统实现方式:
package com.cheng.demo;
/**
* @Author chengxuehao
* @Date 2022/7/30 22:52
* @Version 1.0
*/
public class TraditionDemo {
public Double calculationPrice(String grade, Double originalPrice) {
//周卡
if (grade.equals("weeksCard")) {
return originalPrice - originalPrice * 0.05;
}
//月卡
if (grade.equals("monthCard")) {
return originalPrice - originalPrice * 0.1;
}
//季卡
if (grade.equals("seasonCard")) {
return originalPrice - originalPrice * 0.15;
}
//年卡
if (grade.equals("yearCard")) {
return originalPrice - originalPrice * 0.2;
}
//普通
return originalPrice;
}
}
策略模式实现:
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 22:54
* @Version 1.0
*/
public interface FitnessUserStrategy {
//计算办卡的价格(抽象方法)
public Double calcPrice(Double price);
}
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 22:56
* @Version 1.0
*/
//周卡用户
public class FitnessWeeksCardUserStrategy implements FitnessUserStrategy {
@Override
public Double calcPrice(Double price) {
return price - price * 0.05;
}
}
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 22:58
* @Version 1.0
*/
//月卡用户
public class FitnessMonthCardUserStrategy implements FitnessUserStrategy{
@Override
public Double calcPrice(Double price) {
return price - price * 0.1;
}
}
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 22:59
* @Version 1.0
*/
//季卡用户
public class FitnessSeasonCardUserStrategy implements FitnessUserStrategy {
@Override
public Double calcPrice(Double price) {
return price - price * 0.15;
}
}
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 23:00
* @Version 1.0
*/
//年卡用户
public class FitnessYearCardUserStrategy implements FitnessUserStrategy {
@Override
public Double calcPrice(Double price) {
return price - price * 0.2;
}
}
上下文:
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 23:02
* @Version 1.0
*/
//负责和具体的策略类交互
public class FitnessUserContext {
private FitnessUserStrategy fitnessUserStrategy;
//构造方法
public FitnessUserContext(FitnessUserStrategy fitnessUserStrategy) {
this.fitnessUserStrategy = fitnessUserStrategy;
}
//计算办卡用户的价格
public Double qoutePrice(Double price) {
return fitnessUserStrategy.calcPrice(price);
}
}
测试:
package com.cheng.strategy;
/**
* @Author chengxuehao
* @Date 2022/7/30 23:04
* @Version 1.0
*/
//测试类
public class FitnessApplication {
public static void main(String[] args) {
//具体行为策略
FitnessUserStrategy weeksCardUserStrategy = new FitnessWeeksCardUserStrategy();
FitnessUserStrategy monthCardUserStrategy = new FitnessMonthCardUserStrategy();
FitnessUserStrategy seasonCardUserStrategy = new FitnessSeasonCardUserStrategy();
FitnessUserStrategy yearCardUserStrategy = new FitnessYearCardUserStrategy();
///用户不同的策略选择
FitnessUserContext weeksCardUserContext = new FitnessUserContext(weeksCardUserStrategy);
FitnessUserContext monthCardUserContext = new FitnessUserContext(monthCardUserStrategy);
FitnessUserContext seasonCardUserContext = new FitnessUserContext(seasonCardUserStrategy);
FitnessUserContext yearCardUserContext = new FitnessUserContext(yearCardUserStrategy);
//计算不同周期的价格
System.out.println(weeksCardUserContext.qoutePrice(300d));
System.out.println(monthCardUserContext.qoutePrice(300d));
System.out.println(seasonCardUserContext.qoutePrice(300d));
System.out.println(yearCardUserContext.qoutePrice(300d));
}
}
结果:
针对案例UML图:
策略模式优缺点
优点:
- 策略模式提供了对开闭原则的支持,用户可以在不修改原有逻辑的基础上进行算法或者行为,也可以灵活的增加新的算法或者行为。
- 策略模式提供了可以替换继承关系的方法。
- 策略模式提供了管理有关算法的方法。
- 策略模式可以避免使用多重if判断(条件转移)等。
缺点:
- 客户端必须清楚知道每一个策略类(要实现的类),并清楚什么条件下使用哪种策略类。
- 策略模式会生成很多策略类,一定程度上减少对象的数量。
策略模式的使用场景
- 一个系统中使用了多个类或者多个对象,要用于区分它们的行为,可以使用策略模式动态的让一个对象在多个行为中选择所需要的行为。
一般业务中,在银联、微信、支付宝中有采用策略模式。