工厂+策略模式 实现新增题目

工厂模式

工厂模式是设计模式中的一个基本类型,属于创建型模式。它的核心思想是定义一个用于创建对象的接口,但是让子类决定实例化哪一个类。工厂模式让对象的实例化过程延迟到子类中进行,从而使得代码更具灵活性和扩展性。

主要分类包括:

  • 简单工厂模式:提供一个创建对象的静态方法,根据传入的参数决定创建哪种类型的对象。
  • 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个产品类。工厂方法使一个类的实例化延迟到其子类。
  • 抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而无需指定它们具体的类。

策略模式

策略模式是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户,让代码更加灵活和可扩展。

在策略模式中,通常会有一个上下文(Context)类,它引用一个策略接口,而具体策略类则实现了这个接口。上下文类在运行时决定使用哪个策略,从而改变行为。

工厂+策略模式的结合

将工厂模式和策略模式结合起来使用,可以实现非常灵活的设计。具体来说,可以利用工厂模式来创建不同的策略对象,而策略模式则负责定义这些对象的行为。

例如,假设有一个系统需要根据不同的业务规则执行不同的计算逻辑。可以定义一个策略接口(如CalculationStrategy),然后有多个实现类(如DiscountStrategy, TaxStrategy等)。接着,使用工厂模式(如CalculationStrategyFactory)根据输入的条件(比如业务类型)创建对应的策略对象。这样,系统不仅能够轻松地添加新的计算逻辑(只需增加策略类和更新工厂逻辑),还能在运行时动态选择合适的策略,极大地增强了系统的可维护性和扩展性。

本文将通过工厂+策略模式对刷题社区中新增题目进行设计:

问题所在:

//假设新增题目都写在主流程里面
//我们则需要判断type,单选需要调用单选的service,多选要调用多选的service,这会导致出现一大堆的if语句判别题目情况再分类进入
//因此选取一个策略模式+工厂模式的形式,一个工厂包含了四种题目类型,根据传入的type值做一个映射关系选择处理方法。
首先我们定义一个枚举类声明不同题目类型情况
package com.jingdianjichi.subject.commom.enums;

import lombok.Getter;

/**
 * 分类类型枚举
 * 
 * @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;
    }

}

然后定义一个typehandler接口类

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

import com.jingdianjichi.subject.commom.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.subject.domain.entiy.SubjectInfoBO;

public interface SubjectTypeHandler {
    /**
     * 枚举识别
     */
    SubjectInfoTypeEnum getHandlerType();

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

    /**
     * 实际的题目的插入
     */
   // SubjectOptionBO query(int subjectId);
}

然后设计我们不同题目的具体实现逻辑

import com.jingdianjichi.subject.infra.basic.service.SubjectRadioService;

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

/**
 * 单选题目策略类
 *
 * @author :juziweifenda
 * @date : 2023/7/24
 *
 */
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.commom.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.subject.domain.entiy.SubjectInfoBO;
/**
 * 判断题目策略类
 *
 * @author :juziweifenda
 * @date : 2023/7/24
 *
 */
public class JudgeTypeHandler implements SubjectTypeHandler {
    @Override
    public SubjectInfoTypeEnum getHandlerType() {
        return SubjectInfoTypeEnum.JUDGE;
    }

    @Override
    public void add(SubjectInfoBO subjectInfoBO) {
        //单选实际插入逻辑


    }
}

其他题目逻辑不在赘述展示

工厂方法实现

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);
        }

    }
}

最后serviceimpl类引入工厂实现映射

package com.jingdianjichi.subject.domain.service.impl;


import com.alibaba.fastjson.JSON;
import com.jingdianjichi.subject.commom.enums.IsDeletedFlagEnum;
import com.jingdianjichi.subject.domain.convert.SubjectInfoConverter;
import com.jingdianjichi.subject.domain.entiy.SubjectInfoBO;
import com.jingdianjichi.subject.domain.handler.subject.SubjectTypeHandler;
import com.jingdianjichi.subject.domain.handler.subject.SubjectTypeHandlerFactory;
import com.jingdianjichi.subject.domain.service.SubjectInfoDomainService;
import com.jingdianjichi.subject.infra.basic.entity.SubjectInfo;
import com.jingdianjichi.subject.infra.basic.entity.SubjectMapping;
import com.jingdianjichi.subject.infra.basic.service.SubjectInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;


@Service
@Slf4j
public class SubjectInfoDomainServiceImpl implements SubjectInfoDomainService {

        @Resource
        private SubjectInfoService subjectInfoService;

        @Resource
        private SubjectTypeHandlerFactory subjectTypeHandlerFactory;


    @Override
    public void add(SubjectInfoBO subjectInfoBO) {
        if(log.isInfoEnabled()){
            log.info("SubjectInfoDomainServiceImpl.add.bo:{}", JSON.toJSONString(subjectInfoBO));
        }
        //假设都写在主流程里面
        //需要判断type,单选需要调用单选的service,多选要调用多选的service,这会导致出现一大堆的if语句判别题目情况再分类进入
        //因此选取一个策略模式+工厂模式的形式,一个工厂包含了四种题目类型,根据传入的type值做一个映射关系选择处理方法。
        SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBO);
        subjectInfoService.insert(subjectInfo);
        //引入工厂
        SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfoBO.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));
                subjectMapping.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
                mappingList.add(subjectMapping);
                //调用service
            });

        });
    }

}

 

 

posted @ 2024-07-12 16:24  橘子味芬达水  阅读(17)  评论(0编辑  收藏  举报