设计模式学习笔记-----抽象策略模式

抽象策略模式由五个核心组件组成

策略接口

定义所有策略的统一规范,是策略模式的 "契约"

  • mark():策略的唯一标识(类似字典的 key),默认返回 null,需具体策略实现类重写(如InterviewSubjectHandler返回面试题类型标识)。
  • patternMatchMark():策略的模糊匹配标识(支持正则),用于复杂场景下的模式匹配(非必需实现)。
  • execute(REQUEST):无返回值的策略执行方法(默认空实现,按需重写)。
  • executeResp(REQUEST):有返回值的策略执行方法(默认返回 null,按需重写)。
java 复制代码
/**
 * 策略执行抽象
 */
public interface AbstractExecuteStrategy<REQUEST, RESPONSE> {

    /**
     * 执行策略标识
     */
    default String mark() {
        return null;
    }

    /**
     * 执行策略范匹配标识
     */
    default String patternMatchMark() {
        return null;
    }

    /**
     * 执行策略
     *
     * @param requestParam 执行策略入参
     */
    default void execute(REQUEST requestParam) {

    }

    /**
     * 执行策略,带返回值
     *
     * @param requestParam 执行策略入参
     * @return 执行策略后返回值
     */
    default RESPONSE executeResp(REQUEST requestParam) {
        return null;
    }
}

所有方法均为default(默认方法),允许策略实现类按需重写(无需实现所有方法),降低接口实现成本。

策略选择器

策略的 "管理者",负责策略的注册、查找和执行调度,是策略模式的核心上下文(Context)

  • 策略注册 :实现ApplicationListener,在应用初始化时(onApplicationEvent)从 Spring 容器中获取所有AbstractExecuteStrategy实现类,存入abstractExecuteStrategyMap(key 为mark(),value 为策略实例),并校验mark唯一性(避免冲突)。
  • 策略查找choose()方法支持两种查找方式:
    • 精确匹配:通过mark直接从 map 中获取策略。
    • 模糊匹配:当predicateFlag=true时,用patternMatchMark()的正则匹配mark,适合多标识对应同一策略的场景。
  • 策略执行 :提供chooseAndExecute()(无返回值)和chooseAndExecuteResp()(有返回值)方法,简化 "查找 + 执行" 的调用流程。
java 复制代码
/**
 * 策略选择器
 */
public class AbstractStrategyChoose implements ApplicationListener<ApplicationInitializingEvent> {

    /**
     * 执行策略集合
     */
    private final Map<String, AbstractExecuteStrategy> abstractExecuteStrategyMap = new HashMap<>();

    /**
     * 根据 mark 查询具体策略
     *
     * @param mark          策略标识
     * @param predicateFlag 匹配范解析标识
     * @return 实际执行策略
     */
    public AbstractExecuteStrategy choose(String mark, Boolean predicateFlag) {
        if (predicateFlag != null && predicateFlag) {
            return abstractExecuteStrategyMap.values().stream()
                    .filter(each -> StringUtils.hasText(each.patternMatchMark()))
                    .filter(each -> Pattern.compile(each.patternMatchMark()).matcher(mark).matches())
                    .findFirst()
                    .orElseThrow(() -> new ServiceException("策略未定义"));
        }
        return Optional.ofNullable(abstractExecuteStrategyMap.get(mark))
                .orElseThrow(() -> new ServiceException(String.format("[%s] 策略未定义", mark)));
    }

    /**
     * 根据 mark 查询具体策略并执行
     *
     * @param mark         策略标识
     * @param requestParam 执行策略入参
     * @param <REQUEST>    执行策略入参范型
     */
    public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam) {
        AbstractExecuteStrategy executeStrategy = choose(mark, null);
        executeStrategy.execute(requestParam);
    }

    /**
     * 根据 mark 查询具体策略并执行
     *
     * @param mark          策略标识
     * @param requestParam  执行策略入参
     * @param predicateFlag 匹配范解析标识
     * @param <REQUEST>     执行策略入参范型
     */
    public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam, Boolean predicateFlag) {
        AbstractExecuteStrategy executeStrategy = choose(mark, predicateFlag);
        executeStrategy.execute(requestParam);
    }

    /**
     * 根据 mark 查询具体策略并执行,带返回结果
     *
     * @param mark         策略标识
     * @param requestParam 执行策略入参
     * @param <REQUEST>    执行策略入参范型
     * @param <RESPONSE>   执行策略出参范型
     * @return
     */
    public <REQUEST, RESPONSE> RESPONSE chooseAndExecuteResp(String mark, REQUEST requestParam) {
        AbstractExecuteStrategy executeStrategy = choose(mark, null);
        return (RESPONSE) executeStrategy.executeResp(requestParam);
    }

    @Override
    public void onApplicationEvent(ApplicationInitializingEvent event) {
        Map<String, AbstractExecuteStrategy> actual = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);
        actual.forEach((beanName, bean) -> {
            AbstractExecuteStrategy beanExist = abstractExecuteStrategyMap.get(bean.mark());
            if (beanExist != null) {
                throw new ServiceException(String.format("[%s] Duplicate execution policy", bean.mark()));
            }
            abstractExecuteStrategyMap.put(bean.mark(), bean);
        });
    }
}

自动配置类

整合 Spring 容器,将策略选择器AbstractStrategyChoose注册为 Spring Bean,使其能被全局注入使用。通过 Spring 的自动配置机制,无需手动创建AbstractStrategyChoose实例,简化了策略模式的使用成本。

java 复制代码
/**
 * 设计模式自动装配
 */
@ImportAutoConfiguration(ApplicationBaseAutoConfiguration.class)
@Configuration
public class DesignPatternAutoConfiguration {

    /**
     * 策略模式选择器
     */
    @Bean
    public AbstractStrategyChoose abstractStrategyChoose() {
        return new AbstractStrategyChoose();
    }


}

策略模板类

作为策略的 "中间层",封装通用逻辑,避免具体策略类重复编码(结合了模板模式思想)。

通过抽象类提取共性逻辑,具体策略类只需关注自身特有的业务逻辑

java 复制代码
@Component
public abstract class AbstractQuestionAddAndGetTemplate implements AbstractExecuteStrategy<QuestionInfoDTO, QuestionInfoVO> {

    @Resource
    private QuestionInfoDao questionInfoDao;


    protected QuestionInfoVO buildQuestionInfoVO(QuestionInfoDTO questionInfoDTO) {
        QuestionInfo questionInfo = questionInfoDao.queryById(questionInfoDTO.getId());
        return QuestionInfoVO.builder()
                .id(questionInfo.getId())
                .createdTime(questionInfo.getCreatedTime())
                .createdBy(questionInfo.getCreatedBy())
                .subjectDifficult(questionInfo.getSubjectDifficult())
                .subjectParse(questionInfo.getSubjectParse())
                .updateTime(questionInfo.getUpdateTime())
                .updateBy(questionInfo.getUpdateBy())
                .subjectType(questionInfo.getSubjectType())
                .subjectName(questionInfo.getSubjectName())
                .settleName(questionInfo.getSettleName())
                .build();
    }



}

具体策略类

策略模式的 "具体实现者",负责特定场景的业务逻辑。

java 复制代码
@Component
public class InterviewSubjectHandler extends AbstractQuestionAddAndGetTemplate {

    @Resource
    private QuestionInterviewDao questionInterviewDao;


    @Override
    public String mark() {
        return QuestionInfoTypeEnum.INTERVIEW.getDesc();
    }


    @Override
    public void execute(QuestionInfoDTO requestParam) {
        QuestionInterview questionInterview = QuestionInterview.builder()
                .subjectId(Math.toIntExact(requestParam.getId()))
                .createdBy(requestParam.getCreatedBy())
                .subjectAnswer(requestParam.getSubjectAnswer())
                .isDeleted(IsDeletedFlagEnum.UN_DELETED.getCode())
                .createdTime(new Date())
                .updateTime(new Date())
                .build();
        questionInterviewDao.insert(questionInterview);
    }


    @Override
    public QuestionInfoVO executeResp(QuestionInfoDTO requestParam) {
        QuestionInfoVO questionInfoVO = buildQuestionInfoVO(requestParam);
        QuestionInterview questionInterview = questionInterviewDao.queryById(requestParam.getId());
        questionInfoVO.setSubjectAnswer(questionInterview.getSubjectAnswer());
        return questionInfoVO;
    }

}

执行流程

  • Spring 容器初始化时,AbstractStrategyChoose监听ApplicationInitializingEvent事件。
  • 从容器中扫描到InterviewSubjectHandler(实现了AbstractExecuteStrategy),将其mark()(面试题标识)作为 key,实例作为 value,存入abstractExecuteStrategyMap
  • 当需要处理面试题时,调用AbstractStrategyChoose.chooseAndExecute("面试题标识", requestParam)
  • 选择器通过mark从 map 中找到InterviewSubjectHandler实例,调用其execute()方法执行新增逻辑。

总结

这套抽象策略模式通过接口定义规范选择器管理策略Spring 自动配置模板类复用逻辑的组合设计,实现了策略的 "定义 - 注册 - 选择 - 执行" 全流程自动化,既保证了业务逻辑的解耦,又提供了极高的扩展性和灵活性,非常适合业务场景多变、需要频繁新增策略的系统(如多类型题目处理场景)。