策略模式-通过枚举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与具体的检查类,对代码进行解耦。但解耦不多,不如工厂+策略的方式。

相关推荐
张小姐的猫2 天前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
笨拙的老猴子9 天前
小明学架构师的第七课:策略模式:告别if-else的选择困难症
系统架构·策略模式
肖爱Kun9 天前
C++设计策略模式
开发语言·c++·策略模式
折哥的程序人生 · 物流技术专研11 天前
Java 23 种设计模式:从踩坑到精通 | 番外:策略 vs 模板方法 —— 组合与继承的终极对决
java·策略模式·java面试·comparator·模版方法模式·java设计模式·从踩坑到精通
折哥的程序人生 · 物流技术专研11 天前
Java 23 种设计模式:从踩坑到精通 | 番外:状态 vs 策略 —— if-else 消除的两条路,你走对了吗?
java·spring·状态模式·策略模式·java面试·java设计模式·从踩坑到精通
ttod_qzstudio13 天前
【软考设计模式】策略模式:算法族的封装与动态切换精讲
设计模式·策略模式
儒雅的名14 天前
GoF设计模式——策略模式
设计模式·bash·策略模式
折哥的程序人生 · 物流技术专研14 天前
第4篇:Lambda 简化策略模式(Java 8+)
java·设计模式·策略模式·函数式编程·lambda·代码简化·扩充系列
在水一缸15 天前
拒绝被打扰:深度解析 macOS 进程守护与“反自动启动”攻防战
macos·策略模式·用户体验·进程守护·自动启动·系统权限
折哥的程序人生 · 物流技术专研15 天前
第3篇:手写促销策略引擎(满减、打折、立减)
java·设计模式·策略模式·开闭原则·编程实战·扩充系列·促销引擎