微服务项目 工厂+策略模式 以及案例

       在微服务项目中,策略加工厂模式是一种设计模式,用于解决在不同情况下需要使用不同策略的问题。该模式结合了策略模式和工厂模式的特点,使得系统更具灵活性和可扩展性。

一:策略模式

  • 策略模式是一种行为设计模式,它定义了一系列算法,并将每个算法封装到单独的类中,使得它们可以相互替换。这样可以使得算法的变化独立于使用算法的客户端。在微服务项目中,
  • 策略模式可用于处理不同的业务场景或者应用场景,每个策略对应一个具体的算法,系统可以根据需要动态地选择和切换策略。

二:工厂模式

  • 工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方式,通过工厂方法来创建对象,而不是在客户端直接使用 new 关键字创建对象。
  • 在微服务项目中,工厂模式可用于根据条件动态创建对象,封装了对象创建的逻辑,使得系统更加灵活,降低了客户端与具体类的耦合度。

      策略加工厂模式将这两种模式结合起来,具体体现在以下几点:

  • 定义一个策略接口,包含多个具体策略所需的方法。
  • 实现多个具体策略类,每个具体策略类实现策略接口,并提供具体的算法逻辑。
  • 定义一个工厂类,负责根据条件选择合适的策略并创建相应的策略对象。
  • 在微服务项目中,根据不同的业务需求,通过工厂类选择合适的策略对象,从而实现动态选择算法的功能,使得系统更具弹性和可维护性。

三:小案例

   例如:一个刷题业务,需要在题库中新增题目,但是题目分为多选题、简答题、判断题、单选题各个题型。我们如果按照传统的模式去进行该接口的实现的话,会造成代码冗余if else特别多。如果使用工厂+策略这个设计模式的话就会消除很多的if else可以使得代码结构更加的清晰,每个功能和模块都会由明确的职责和接口,易于理解和维护。而且有很好的可拓展性

首先我们先定义题目类型的枚举

import lombok.Getter;

/**
     * 题目类型枚举
     * 1单选 2多选 3判断 4简答
     * @author: ChickenWing
     * @date: 2023/10/3
     */
    @Getter
    public enum SubjectInfoTypeEnum {

        RADIO(1,"单选"),
        MULTIPLE(2,"多选"),
        JUDGE(3,"判断"),
        BRIEF(4,"简答"),
        ;

        public int code;

        public String desc;

        SubjectInfoTypeEnum(int code, String desc){
            this.code = code;
            this.desc = desc;
        }

        public static SubjectInfoTypeEnum getByCode(int codeVal){
            for(SubjectInfoTypeEnum resultCodeEnum : SubjectInfoTypeEnum.values()){
                if(resultCodeEnum.code == codeVal){
                    return resultCodeEnum;
                }
            }
            return null;
        }

    }

   我们创建一个接口 来进行枚举身份的识别 以及写上 该题型将要实现的方法如增删改查 我写了个

add的方法 增加单选题目!

import com.jingdianjichi.subject.common.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.subject.domain.entity.SubjectInfoBO;

public interface SubjectTypeHandler {
    /**
     * 枚举身份的识别
     * @return
     */
    SubjectInfoTypeEnum getHandlerType();

    /**
     * 实际的题目的插入
     * @param subjectInfoBO
     */
    void add(SubjectInfoBO subjectInfoBO);
}

      然后我们要根据获得题目枚举的具体类型(题目类型 例如:单选、多选)来创建策略类实现我们上面所写的那个策略接口

我们下面举个例如单选题

import com.jingdianjichi.subject.common.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.subject.domain.convert.RadioSubjectConverter;
import com.jingdianjichi.subject.domain.entity.SubjectInfoBO;
import com.jingdianjichi.subject.infra.basic.entity.SubjectRadio;
import com.jingdianjichi.subject.infra.basic.service.SubjectRadioService;
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509SubjectNameResolver;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 单选的题目的策略类
 */
@Component
public class RadioTypeHandler implements SubjectTypeHandler {
    @Resource
private SubjectRadioService subjectRadioService;

    @Override
    public SubjectInfoTypeEnum getHandlerType() {
        return SubjectInfoTypeEnum.RADIO;
    }

    @Override
    public void add(SubjectInfoBO subjectInfoBO) {
           //单选题目的插入
        List<SubjectRadio> subjectRadioList=new LinkedList<>();
        subjectInfoBO.getOptionList().forEach(option->{
          SubjectRadio subjectRadio= RadioSubjectConverter.INSTANCE.convertBOToEntity(option);
          subjectRadio.setSubjectId(subjectInfoBO.getId());
          subjectRadioList.add(subjectRadio);
        });
        subjectRadioService.batchinsert(subjectRadioList);
    }
}

这是多选题的策略类 下面的其他类型的题目的策略类我就不一一赘述了 跟多选题一样 实现那个策略接口。

package com.jingdianjichi.subject.domain.handler.subject;

import com.jingdianjichi.subject.common.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.subject.domain.entity.SubjectInfoBO;
import org.springframework.stereotype.Component;

/**
 * 多选的题目的策略类
 */
@Component
public class MultipleTypeHandler implements SubjectTypeHandler{
    @Override
    public SubjectInfoTypeEnum getHandlerType() {
        return SubjectInfoTypeEnum.MULTIPLE;
    }

    @Override
    public void add(SubjectInfoBO subjectInfoBO) {

    }
}

   如下图所示

      然后我们就需要创建一个工厂类

import com.jingdianjichi.subject.common.enums.SubjectInfoTypeEnum;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 题目类型工厂
 */
@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);

    }


    @Override
    public void afterPropertiesSet() throws Exception {
        for (SubjectTypeHandler subjectTypeHandler : subjectTypeHandlerList) {
            handlerMap.put(subjectTypeHandler.getHandlerType(),subjectTypeHandler);
        }
    }
}

工厂类要继承InitializingBean 接口

InitializingBean是spring为bean的初始化提供了一种新的方式,里面只有一个方法afterPropertiesSet,作用就是实现这个接口或者实现了继承InitializingBean的方法的bean都要执行这个方法。

最后我们在Controller层中去实现单选题目的增加

private SubjectInfoDomainService subjectInfoDomainService;
    /**
     * 新增题目
     *
     * @return
     */
    @PostMapping("/add")
    public Result<Boolean> add(@RequestBody SubjectInfoDTO subjectInfoDTO) {
        try {

            if (log.isDebugEnabled()){
                log.info("SubjectController.add.dto:{}", JSON.toJSONString(subjectInfoDTO));

            }
            //参数校验
            Preconditions.checkArgument(!StringUtils.isBlank(subjectInfoDTO.getSubjectName()),"题目名称不能为空");
            Preconditions.checkNotNull(subjectInfoDTO.getSubjectDifficult(),"难度不能为空");
            Preconditions.checkNotNull(subjectInfoDTO.getSubjectType(),"题目类型为空");
            Preconditions.checkNotNull(subjectInfoDTO.getSubjectScore(),"题目分数为空");
            Preconditions.checkNotNull(!CollectionUtils.isEmpty(subjectInfoDTO.getCategoryIds()),
                    "分类id不能为空");
            Preconditions.checkNotNull(!CollectionUtils.isEmpty(subjectInfoDTO.getLabelIds()),
                    "标签id不能为空");
            SubjectInfoBO subjectInfoBO = SubjectInfoDTOConverter.INSTANCE.
                    convertDTOTOBO(subjectInfoDTO);
            List<SubjectAnswerBO> subjectAnsweBOList = SubjectAnswerDTOConverter.INSTANCE.
                    convertListDTOToBO(subjectInfoDTO.getOptionList());
            subjectInfoBO.setOptionList(subjectAnsweBOList);
            subjectInfoDomainService.add(subjectInfoBO);

            return Result.ok(true);
        }catch (Exception e){
            log.error("SubjectController.add.error:{}",e.getMessage(),e);
            return Result.fail("新增题目失败");
        }
    }

  Service层

@Override
    public void add(SubjectInfoBO subjectInfoBO) {
        if (log.isDebugEnabled()) {
            log.info("SubjectInfoDomainServiceImpl.add.dto:{}", JSON.toJSONString(subjectInfoBO));

        }
        //工厂+策略
        SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBOToInfo(subjectInfoBO);
        subjectInfoService.insert(subjectInfo);
        //
        SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());
        handler.add(subjectInfoBO);
        List<Integer> categoryIds = subjectInfoBO.getCategoryIds();
        List<Integer> labelIds = subjectInfoBO.getLabelIds();
        List<SubjectMapping> mappingList=new LinkedList<>();
        categoryIds.forEach(categoryId->{
            labelIds.forEach(labelId->{
                SubjectMapping subjectMapping=new SubjectMapping();
                subjectMapping.setSubjectId(subjectInfo.getId());
                subjectMapping.setCategoryId(Long.valueOf(categoryId));
                subjectMapping.setLabelId(Long.valueOf(labelId));
                mappingList.add(subjectMapping);
            });
        });
        subjectMappingService.batchInsert(mappingList);


    }

  工厂类SubjectTypeHandlerFactory就相当于帮我们创建了题型对应的策略实例,之后我们只需要调用里面的add方法即可,如果不用工厂模式,我们就需要在代码里手动的创建这个题型对应的策略实例。这个工厂模式,就相当与让工厂类代替我们创建策略实例。

希望大家多多关注我,我会持续更新Spring Boot项目中的干货,有什么不足的欢迎评论区留言和私信留言!第一时间回复,关注我 送Java学习资料以及干货!!!

  • 42
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值