策略模式-通过枚举newInstance替代工厂

策略模式-使用枚举newInstance


前言

很久没写文章了~~

吐槽下:入职新公司后,基本在搬砖,我爱劳动我光荣~

遇到一个小需求:根据接口入参-不同类型,进行不同字段的检查。不想写if...else嵌套,就写了个最简单的策略模式。


一、枚举类:MarkCheckDataTypeEnum

创建一个枚举类,将业务实现类作为枚举的一个属性,

如:

STD_PEOPLE("std_people", MarkPeopleChecker.class)

java 复制代码
public enum MarkCheckDataTypeEnum {
    /**
     * 主体-人
     */
    STD_PEOPLE("std_people", MarkPeopleChecker.class),
    /**
     * 主体-房屋
     */
    STD_HOUSE("std_house", MarkHouseChecker.class),
    /**
     * 主体-小区
     */
    STD_RESIDENTIAL("std_residential", MarkResidentialChecker.class),
    /**
     * 主体-商铺
     */
    STD_BUSINESS("std_business", MarkBusinessChecker.class),
    /**
     * 主体-企业
     */
    STD_ENTERPRISE("std_enterprise", MarkEnterpriseChecker.class),
    /**
     * 主体-区域
     */
    STD_PARK("std_park", MarkParkChecker.class),

    ;

    /**
     * 主体类型
     */
    private String dataType;
    /**
     * 主体的预检查类
     */
    private Class<?> checker;

    MarkCheckDataTypeEnum(String dataType, Class checker) {
        this.dataType = dataType;
        this.checker = checker;
    }

    public String getDataType() {
        return dataType;
    }

    public void setDataType(String dataType) {
        this.dataType = dataType;
    }

    public Class<?> getChecker() {
        return checker;
    }

    public void setChecker(Class<?> checker) {
        this.checker = checker;
    }

    /**
     * 根据主体获取检查类
     *
     * @param dataType 主体类型
     * @return 检查类
     * @throws Exception new实例异常
     */
    public static AbstractMarkChecker getMarkChecker(String dataType) throws Exception {
        for (MarkCheckDataTypeEnum markCheckDataTypeEnum : MarkCheckDataTypeEnum.values()) {
            if (markCheckDataTypeEnum.getDataType().equals(dataType)) {
                return (AbstractMarkChecker) markCheckDataTypeEnum.getChecker().newInstance();
            }
        }
        return MarkCommonChecker.class.newInstance();
    }
}

二、抽象类:AbstractMarkChecker

BusinessException这个是自定义异常,用于抛出检查类:检查不通过的原因。

1:有点编码基础的,也可以换成自己的异常类

2:或者把不通过的原因返回出来,如:

java 复制代码
public abstract String check(List<String> assetFieldNameList);

我的代码如下:

java 复制代码
import lobster.base.exception.BusinessException;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 保存标注时,进行必要信息检查
 * 人:
 * 未检测到【证件号】或者【姓名】+【手机号】标注字段,而有其他人员非必要信息字段标注的情况下
 * 提示:您的标注信息未包含人员必要信息字段【证件号】或【姓名+手机号】,可能导致人员信息数据无法入库,请仔细检查。
 * <p>
 * 房屋:
 * 未检测到【房屋地址】或者【楼栋+单元+楼层+房号】或者【房号】标注字段,而有其他房屋非必要信息字段标注的情况下
 * 提示:您的标注信息未包含房屋必要信息字段【房屋地址】或【楼栋+单元+楼层+房号】或【房号】,可能导致房屋信息数据无法入库,请仔细检查。
 * <p>
 * <p>
 * 小区:
 * 未检测到【小区名】标注字段,而有其他小区非必要信息字段标注的情况下
 * 提示:您的标注信息未包含小区必要信息字段【小区名】,可能导致小区信息数据无法入库,请仔细检查。
 * <p>
 * 商铺:
 * 未检测到【商铺名称+商铺地址】标注字段,而有其他商铺非必要信息字段标注的情况下
 * 提示:您的标注信息未包含商铺必要信息字段【商铺名称+商铺地址】,可能导致商铺信息数据无法入库,请仔细检查。
 * <p>
 * 企业:
 * 未检测到【企业名称+企业地址】标注字段,而有其他企业非必要信息字段标注的情况下
 * 提示:您的标注信息未包含企业必要信息字段【企业名称+企业地址】,可能导致企业信息数据无法入库,请仔细检查。
 * <p>
 * 区域:
 * 未检测到【区域名称】标注字段,而有其他区域非必要信息字段标注的情况下
 * 提示:您的标注信息未包含区域必要信息字段【区域名称】,可能导致区域信息数据无法入库,请仔细检查。
 *
 * @author lobster
 */
@Service
public abstract class AbstractMarkChecker {

    /**
     * 检查主体必要字段
     *
     * @param assetFieldNameList 当前主体,标注时选择的字段
     * @throws BusinessException 业务异常
     */
    public abstract void check(List<String> assetFieldNameList) throws BusinessException;
}

三、检查类:MarkPeopleChecker

检查类和MarkCheckDataTypeEnum的checker对应。

这里只贴一个MarkPeopleChecker,检查类都差不多

java 复制代码
import lobster.base.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 人:
 * 未检测到【证件号】或者【姓名】+【手机号】标注字段,而有其他人员非必要信息字段标注的情况下
 * 提示:您的标注信息未包含人员必要信息字段【证件号】或【姓名+手机号】,可能导致人员信息数据无法入库,请仔细检查。
 *
 * @author lobster
 */
@Slf4j
@Service
public class MarkPeopleChecker extends AbstractMarkChecker {
    private static final String NAME = "name";
    private static final String ID_CARD = "id_card";
    private static final String MOBILE = "mobile";

    @Override
    public void check(List<String> assetFieldNameList) throws BusinessException {
        boolean containsName = assetFieldNameList.contains(NAME);
        boolean containsIdCard = assetFieldNameList.contains(ID_CARD);
        boolean containsMobile = assetFieldNameList.contains(MOBILE);
        if (containsIdCard) {
            log.info("标注主体:std_people 存在【证件号】");
            return;
        }
        if (containsName && containsMobile) {
            log.info("标注主体:std_people 存在【姓名】+【手机号】");
            return;
        }
        throw new BusinessException(500, "您的标注信息未包含人员必要信息字段【证件号】或【姓名+手机号】,可能导致人员信息数据无法入库,请仔细检查");
    }
}

四、demo演示

直接执行main方法就行

代码如下(示例):

java 复制代码
import com.example.springDemo.markprecheck.MarkCheckDataTypeEnum;
import com.google.common.collect.Lists;
import lobster.base.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController("mark/pre/check")
public class MarkPreCheckController {


    @GetMapping(value = "demo", name = "通过枚举实现策略")
    public static String demo() {
        try {
            MarkCheckDataTypeEnum.getMarkChecker("std_people").check(Lists.newArrayList("name", "sex"));
        } catch (BusinessException e) {
            log.error("出现业务异常:", e);
            return e.getMsg();
        } catch (Exception e) {
            log.error("出现系统异常:", e);
            return e.getMessage();
        }
        return "success";
    }
	//直接执行main方法就行
    public static void main(String[] args) {
        String errorMsg = demo();
        System.out.println(errorMsg);
    }
}

实例代码打印结果:


总结

总来的来,emm~~这个示例很简单,没啥说的。

主要是通过MarkCheckDataTypeEnum.getMarkChecker()来获取检查类实例,然后调用检查类的check方法。

通过扩展枚举类MarkCheckDataTypeEnum与具体的检查类,对代码进行解耦。但解耦不多,不如工厂+策略的方式。

相关推荐
都说名字长不会被发现13 小时前
模版方法 + 策略模式在库存增加/扣减场景下的应用
策略模式·模板方法模式·宏命令·策略聚合·库存设计
默|笙13 小时前
【Linux】进程概念与控制(2)_进程控制
java·linux·策略模式
枫叶林FYL2 天前
Agent/Teakenote 系统(Swarm 架构)深度技术报告
架构·策略模式
苏渡苇3 天前
枚举的高级用法——用枚举实现策略模式和状态机
java·单例模式·策略模式·枚举·状态机·enum
harder3215 天前
Swift 面向协议编程的 RMP 模式
开发语言·ios·mvc·swift·策略模式
skywalk81635 天前
esxi8 虚拟机中怎么安装mac os(纯AI回答,未实践)
策略模式·esxi
廖圣平6 天前
从零开始,福袋直播间脚本研究【八】《策略模式》
开发语言·python·bash·策略模式
爱学习 爱分享9 天前
简单工厂模式和策略模式的区别
简单工厂模式·策略模式
xcntime12 天前
Python中print函数如何实现不换行输出?
策略模式
青春易逝丶13 天前
策略模式
java·开发语言·策略模式