常用设计模式——策略模式

策略模式是什么

策略模式(Strategy):针对一组算法,将每一个算法封装起来,从而使得它们可以相互替换。

比如我们一个软件的会员等级,每一个等级都会有对应的一些等级权益,那么每一个等级权益就对应一个策略

结构

策略模式的通用类图如下:

策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)

1.上下文角色(Context):持有所有策略类的对象,可以根据策略提供相应的算法给客户端使用。

2.抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色提供具体策略类所需的接口。

3.具体策略角色(ConcreteStrategy):继承或实现了抽象策略,封装了相应的算法或行为。

策略模式的优缺点

优点

(1)算法可以自由切换

(2)避免使用多重条件判断

(3)扩展性良好,增加一个策略只需实现接口即可

缺点

(1)策略类数量会增多,每个策略都是一个类,复用性很小

(2)所有的策略类都需要对外暴露

使用场景

1、业务代码需要根据场景不同,切换不同的实现逻辑

2、代码中存在大量 if else 逻辑判断

实例

下面使用策略模式实现会员不同等级的权益领取

抽象策略角色:

java 复制代码
/**
 * 会员抽象策略
 */
public interface MemberStrategy {

    /**
     * 领取会员福利
     */
    void getWeal();

}

具体策略角色:

java 复制代码
/**
 * 等级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

java 复制代码
/**
 * 策略枚举
 */
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工厂中的实例,下面是对应工具类

java 复制代码
@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);
    }

}

上下文角色类

java 复制代码
/**
 * 会员上下文角色
 */
@Component
public class MemberStrategyContext {

    /**
     * 根据入参类型获取对应的策略类
     * @param type
     * @return
     */
    public MemberStrategy getMemberStrategy(String type){
        MemberStrategy memberStrategy = ApplicationContextUtil.getBean(MemberEnum.getStrategyClass(type));
        return memberStrategy;
    }

}

测试类

java 复制代码
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();

    }

}
相关推荐
rannn_1115 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
灵感菇_5 小时前
Java HashMap全面解析
java·开发语言
qq_12498707535 小时前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
短剑重铸之日5 小时前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
若鱼19195 小时前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
觉醒大王5 小时前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
努力学编程呀(๑•ี_เ•ี๑)5 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
feasibility.5 小时前
AI 编程助手进阶指南:从 Claude Code 到 OpenCode 的工程化经验总结
人工智能·经验分享·设计模式·自动化·agi·skills·opencode
码农小卡拉6 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot
向上的车轮6 小时前
为什么.NET(C#)转 Java 开发时常常在“吐槽”Java:checked exception
java·c#·.net