前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >代码结构优化——工厂+策略模式解耦条件判断

代码结构优化——工厂+策略模式解耦条件判断

原创
作者头像
xiao李
发布2025-03-23 10:36:12
发布2025-03-23 10:36:12
1110
举报
文章被收录于专栏:Java相关Java相关

我们先来看一个数据库表结构

这个库是记录题目的信息,主表下分了四种题目表

如果我们想新增题目信息,不难想到,最简单、最直接的办法那肯定是在service层直接做多个if-else来调用多个dao(mapper)

代码语言:txt
复制
@Override
public void add(SubjectInfoBO subjectInfoBO) {
    if (log.isInfoEnabled()) {
        log.info("SubjectInfoDomainServiceImpl.add.bo:{}", JSON.toJSONString(subjectInfoBO));
    }
    /*
     * 假设都写在主流程里面
     * 判断type,单选的调用单选的service,多选的调用多选的
     * 一大堆if
     */
    // 主表
    SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBO);
    subjectInfoService.insert(subjectInfo);
 
    // 一大堆if-else,然后不同的service
    // ......Service.insert(......);
    
 
    // 省略多表处理……    
}

这样做?

其他人可能会好好问候你一下😁

这样的代码中,有很多if-else,并且还有很多的if-else嵌套,无论是可读性还是可维护性都非常低。

如果后续更改其中一个题型那么在原方法上更改很有可能会导致其他的插入出现异常。

那么这个策略模式怎么实现呢?

策略模式

先定义一个重要的接口,我这里都定义在了handler里边了

代码语言:txt
复制
public interface SubjectTypeHandler {
 
    /**
     * 枚举身份的识别
     *
     * @return
     */
    SubjectInfoTypeEnum getHandlerType();
 
    /**
     * 实际的题目的插入
     *
     * @param subjectInfoBO
     */
    void add(SubjectInfoBO subjectInfoBO);
}

然后定义四个题目类(单选、多选、判断、简答)分别实现这个接口

代码语言:txt
复制
@Component
@RequiredArgsConstructor
public class BriefTypeHandler implements SubjectTypeHandler {
 
    private final SubjectBriefService subjectBriefService;
    /**
     * 枚举身份的识别
     *
     * @return 哪个枚举出来的
     */
    @Override
    public SubjectInfoTypeEnum getHandlerType() {
        return SubjectInfoTypeEnum.BRIEF;  // 4 简答
    }
 
    /**
     * 实际的题目的插入
     */
    @Override
    public void add(SubjectInfoBO subjectInfoBO) {
        // 简答题目的插入
        // set方法......
        subjectBriefService.insert(subjectBrief);
    }
}

在上面代码中,直接定义了一个枚举来表示type了

其他类和上面方法一致

工厂模式

上面的策略做完之后,我们需要定义一个工厂来做处理,这个工厂我也放在了上面一堆类的包下面,也就是handler中。

代码语言:txt
复制
/**
 * 题目类型处理器工厂
 */
@Component
public class SubjectTypeHandlerFactory implements InitializingBean {
 
    @Resource
    private List<SubjectTypeHandler> subjectTypeHandlerList;
 
    private Map<SubjectInfoTypeEnum, SubjectTypeHandler> handlerMap = new HashMap<>();
 
    public SubjectTypeHandler getHandler(int subjectType) {
        SubjectInfoTypeEnum subjectInfoTypeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
        return handlerMap.get(subjectInfoTypeEnum);
    }
 
    /**
     * 启动时加载
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        for (SubjectTypeHandler subjectTypeHandler : subjectTypeHandlerList) {
            handlerMap.put(subjectTypeHandler.getHandlerType(), subjectTypeHandler);
        }
    }
}

这里实现了Spring的InitializingBean接口,InitializingBean是Spring提供的拓展性接口,InitializingBean接口为bean提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是实现该接口的类,在bean的属性初始化后都会执行该方法。

说人话就是,启动后直接加载……

这样呢,我们在调用service的时候,就不会有那么多的if-else了

代码语言:txt
复制
public void add(SubjectInfoBO subjectInfoBO) {
    if (log.isInfoEnabled()) {
        log.info("SubjectInfoDomainServiceImpl.add.bo:{}", JSON.toJSONString(subjectInfoBO));
    }
    // 主表
    SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBO);
    subjectInfoService.insert(subjectInfo);
 
    // 调用工厂
    SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());
    handler.add(subjectInfoBO);
 
    // 关系表处理
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 策略模式
  • 工厂模式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档