策略模式是什么
策略模式(Strategy):针对一组算法,将每一个算法封装起来,从而使得它们可以相互替换。
比如我们一个软件的会员等级,每一个等级都会有对应的一些等级权益,那么每一个等级权益就对应一个策略
结构
策略模式的通用类图如下:
策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)
1.上下文角色(Context):持有所有策略类的对象,可以根据策略提供相应的算法给客户端使用。
2.抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色提供具体策略类所需的接口。
3.具体策略角色(ConcreteStrategy):继承或实现了抽象策略,封装了相应的算法或行为。
策略模式的优缺点
优点
(1)算法可以自由切换
(2)避免使用多重条件判断
(3)扩展性良好,增加一个策略只需实现接口即可
缺点
(1)策略类数量会增多,每个策略都是一个类,复用性很小
(2)所有的策略类都需要对外暴露
使用场景
1、业务代码需要根据场景不同,切换不同的实现逻辑
2、代码中存在大量 if else 逻辑判断
实例
下面使用策略模式实现会员不同等级的权益领取
抽象策略角色:
/**
* 会员抽象策略
*/
public interface MemberStrategy {
/**
* 领取会员福利
*/
void getWeal();
}
具体策略角色:
/**
* 等级1的会员福利
*/
@Component
public class LV1MemberWeal implements MemberStrategy {
@Override
public void getWeal() {
System.out.println("5元优惠券");
}
}
/**
* 等级2会员福利
*/
@Component
public class LV2MemberWeal implements MemberStrategy{
@Override
public void getWeal() {
System.out.println("10元优惠券");
}
}
上下文角色:
我们可以使用枚举加bean工厂来定义一个上下文角色,避免上下文角色的if-else
策略枚举类
策略枚举类用于获取bean容器中的策略类class
/**
* 策略枚举
*/
public enum MemberEnum {
LV1(LV1MemberWeal.class),
LV2(LV2MemberWeal.class);
;
private Class clazz;
MemberEnum(Class clazz) {
this.clazz = clazz;
}
public static Class getStrategyClass(String name){
return MemberEnum.valueOf(name).clazz;
}
}
使用ApplicationContext可以获取bean工厂中的实例,下面是对应工具类
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
/**
* 将ApplicationContext注入
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
/**
* 根据类型获取bean
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class clazz){
return (T) getApplicationContext().getBean(clazz);
}
/**
* 根据名称获取bean
* @param name
* @param <T>
* @return
*/
public static <T> T getBean(String name){
return (T) getApplicationContext().getBean(name);
}
}
上下文角色类
/**
* 会员上下文角色
*/
@Component
public class MemberStrategyContext {
/**
* 根据入参类型获取对应的策略类
* @param type
* @return
*/
public MemberStrategy getMemberStrategy(String type){
MemberStrategy memberStrategy = ApplicationContextUtil.getBean(MemberEnum.getStrategyClass(type));
return memberStrategy;
}
}
测试类
RunWith(SpringRunner.class) //作用:让当前类在容器环境下进行测试
@SpringBootTest(classes = DemoApplication.class)
public class StrategyTest {
@Autowired
private MemberStrategyContext memberStrategyContext;
@Test
public void testStrategy(){
//根据入参获取对应策略类
MemberStrategy memberStrategy = memberStrategyContext.getMemberStrategy("LV2");
//执行策略类的算法
memberStrategy.getWeal();
}
}