当前位置: 首页 > article >正文

【设计模式-我的思考】套餐模式

imom排故下线-订单状态集查询功能实现(套餐模式)

需求描述
排故下线状态
不排故:未启用排故下线确认配置&订单状态参数值!=(170、180、190)
待排故:启用排故下线确认配置&排故下线确认未执行&订单状态参数值!=(170、180、190)
已排故:启用排故下线确认配置&排故下线确认已执行&订单状态参数值!=(170、180、190)
已入库:订单状态参数值=170、180、190
每种状态的条件是与关系,状态集之间是或关系,多选则查询集合的并集.每个订单只属于其中一种状态集.
需要实现状态集查询,和结果集元素状态标记返回.

套餐模式

这是一种很常见的需求场景,就是对查询条件进行提前设置好套餐,根据用户选择的套餐,实现原本需要复杂配置的多个查询条件组合.

原来的查找条件分字段拆解给用户,用户需要各种条件组合才能看到自己想要的,BA通过对查询条件的组合抽象出来4个状态集合,每个集合包含一系列的字段组合查询,这样的交互模式为状态模式,将复杂留给开发,将便捷留给用户.
分析一下,原来的查询条件是自由组装的,现在在状态集的范围内,是个固定的参数值组合.很容易联想到状态模式来根据用户的选择实现条件的组合放入对象中初始化,选择多个状态则初始化多个对象放入对象集合进行循环查询,将结果集再进行组装.

于是做出如下设计:
在这里插入图片描述

关键代码

TroubleCheckStatus.java //套餐查询对象

public void init(List<String> statusList){
    List<WipOrderInfoQO> queryQO=new List();
    //接收用户套餐选择,对子类对象进行初始化
    if(statusList ==null){
        WipOrderInfoQO object=new WipOrderInfoQO(this);
        queryQO.add(object);
    }else{
        for(String status:statusList){
            WipOrderInfoQO object=new WipOrderInfoQO(status,this);
            queryQO.add(object);
        }
    }
    this.queryList=queryQO;
}


WipOrderInfoQO.java//原有查询对象

public WipOrderInfoQO(TroubleCheckStatus object){
    //将父类的属性初始化到子类对象,实现传递
}

public WipOrderInfoQO(String status,TroubleCheckStatus object){
    //status为套餐名称,可以从枚举或者spring bean中获取配置好的数据,对WipOrderInfoQO的属性进行定制化,套餐分解
}


import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.Getter;

/**
 * className com.sany.mom.qm.troubleshooting.enums.TroubleCheckSetEnum 排故下线状态
 * 不排故:未启用排故下线确认配置&订单状态参数值!=(170、180、190) 待排故:启用排故下线确认配置&排故下线确认未执行&订单状态参数值!=(170、180、190)
 * 已排故:启用排故下线确认配置&排故下线确认已执行&订单状态参数值!=(170、180、190) 已入库:订单状态参数值=170、180、190
 *
 * @author shengfq
 * @date 2024-10-15 11:32
 */
@Getter
public enum TroubleCheckSetEnum {
    NONE("NONE", "不排故", false, false, onProgress()),
    TODO("TODO", "待排故", true, false, onProgress()),
    DONE("DONE", "已排故",  true, true, onProgress()),
    DONE1("DONE1", "已排故",  false, true, onProgress()),
    STOCKED("STOCKED", "已入库", null, null, stockedProgress());

    private static final Map<String, TroubleCheckSetEnum> STATUS_MAP = Arrays.stream(TroubleCheckSetEnum.values())
                    .collect(Collectors.toMap(TroubleCheckSetEnum::getCode, Function.identity()));
    /**
     * 代码
     */
    private String code;
    /**
     * 中文描述
     */
    private String desc;
    /**
     * 是否启用排故下线确认配置
     */
    private Boolean enable;
    /**
     * 排故下线确认状态
     */
    private Boolean executed;
    /**
     * 订单状态子集合
     */
    private List<Integer> progressStatus;

    TroubleCheckSetEnum(String code, String desc, Boolean enable, Boolean executed, List<Integer> progressStatus) {
        this.code = code;
        this.desc = desc;
        this.enable = enable;
        this.executed = executed;
        this.progressStatus = progressStatus;
    }

    /**
     * 非入库状态
     */
    private static List<Integer> onProgress() {
        List<Integer> all= Arrays.stream(ProgressStatusEnum.values())
                        .map(ProgressStatusEnum::getCode).collect(Collectors.toList());
        all.removeAll(stockedProgress());
        return all;
    }

    /**
     * 已入库:订单状态参数值=170、180、190
     */
    private static List<Integer> stockedProgress() {
        return Arrays.asList(ProgressStatusEnum.DELETED.getCode(), ProgressStatusEnum.CLOSED.getCode(),
                        ProgressStatusEnum.STORAGE.getCode());
    }

    /**
     * 根据code获取排故下线实例
     */
    public static TroubleCheckSetEnum ofCode(String code) {
        return STATUS_MAP.get(code);
    }

    /**
     * 根据订单的相关配置信息来计算其排故下线状态实例
     *
     * @param enable 订单类型是否启用排故下线
     * @param executed 订单是否执行了排故下线确认
     * @param progressStatus 订单状态
     */
    public static TroubleCheckSetEnum getInstance(Boolean enable, Boolean executed, Integer progressStatus) {
        TroubleCheckSetEnum troubleCheckSetEnum= Arrays.stream(TroubleCheckSetEnum.values()).filter(i -> i.progressStatus.contains(progressStatus)).findAny().get();
        if(troubleCheckSetEnum==STOCKED){
            return troubleCheckSetEnum;
        }else{
            return Arrays.stream(TroubleCheckSetEnum.values()).filter(i -> i.progressStatus.contains(progressStatus) && i.enable.equals(enable) && i.executed.equals(executed)).findAny().get();
        }
    }
}

总结

在企业级应用开发中,查询条件是复杂的,如果能通过设置套餐来降低系统使用程度,这个产品设计原则就是很好的idea.技术上实现,则是在原有的查询上下文上增加一个状态集父类,通过初始化将套餐与枚举绑定,读取枚举配置好的配方参数对原有参数进行组合,代码侵入程度低,可扩展性强,耦合度低,实则是一个很不错的设计方案.
2024-10-22 晚


http://www.kler.cn/news/366146.html

相关文章:

  • PostgreSQL使用clickhouse_fdw访问ClickHouse
  • <项目代码>YOLOv8煤矿输送带异物识别<目标检测>
  • java智能物流管理系统源码(springboot)
  • 最新版本jdbcutils集成log4j做详细sql日志、自动释放连接...等
  • Python游戏开发超详细第二课/一个小游戏等制作过程(入门级篇共2节)
  • Svelte 5 正式发布:新一代前端框架!
  • 【有啥问啥】CLIP Adapter:提升视觉语言模型性能的利器
  • LeetCode 每周算法 10(多维动态规划、技巧)
  • 银行客户贷款行为数据挖掘与分析
  • 入侵检测算法平台部署LiteAIServer视频智能分析平台行人入侵检测算法
  • 分布式光伏发电系统电气一次部分设计(开题报告3)
  • GFF: Gated Fully Fusion for Semantic Segmentation门控融合语义分割-论文阅读笔记
  • ChainLink 预言机学习
  • 华为OD机试真题-矩形绘制-2024年OD统一考试(E卷)
  • 依赖关系是危险的
  • 深入探讨 HTTP 请求方法:GET、POST、PUT、DELETE 的实用指南
  • 泛型的特点
  • C++《vector》
  • 【实战案例】Django框架使用模板渲染视图页面及异常处理
  • Vscode连接WSL2(Ubuntu20.04)
  • P2818 天使的起誓
  • Linux: network: wireshark IO图的一个问题
  • Matlab学习02-matlab中的数据显示格式及符号变量
  • Flask-SQLAlchemy 组件
  • 排序算法 —— 直接选择排序
  • 在 Vue 渲染模板时,如何保留模板中的 HTML 注释?