真实业务场景使用-模板模式+策略模式组合

news2024/11/19 3:29:13

模板和策略设计模式一般是使用最频繁的设计模式,模板的场景主要是处理一系列相同的流程,将这些流程放到模板里,每个流程里的处理可能有一些不一样的地方,则可以抽象出一个方法,由每一个有实际意义的子类实现。

策略模式:由于总会有不同的实现类,而最终总会要调用实现里,所以用策略模式帮助我们如何调用到实现类里。

1.背景说明

以我自己亲身经历的场景说一下,我接手了之前写好的系统,但是有个问题,一个新建功能,在还没有保存前就先获取了编号,不入库不记录,导致会出现很多人进入相同页面也就分配相同的编号,有一个保存被占用后,其他都无法保存因为编号重复,查看整个系统后发现很多都是这种方式,所以需要优化一下。

思考了一下,业务逻辑是需要记录一个编号值的库表,然后类别不同,再有一个编码值就可以,也就是如下这种方式,设计了如下库表

codetype
20220102goods:商品编码
CD20230205biss:业务编码
23order:序号码值

每次生成编码则将对应的类型的code更新,这样库里永远是新的,处理共性业务就会出现,

1.获取库里当前类型的编码,

2.根据当前编码的值得到新的编码(前一个编码值+1或者其他规则),

3.得到新的编码值则更新到库里,

所有的生成编号逻辑都要经历这三步,那么就抽出来共性用模板方式,唯一不同的是生成新的编码规则,看表里有的是序号,有的是年月日,有的是前缀+年月日,所以生成编码的方法需要抽象化由各个子类实现。

流程出来了,现在看来已经有三个子类了,我们如何在用户使用时精准使用某个具体类呢,这里就采用策略模式,由于策略模式会出现多个if判断的情况,所以这里对策略模式进行优化,采取map映射key获取具体的实现类。

2.UML类图

还是蛮简单的,看下面的UML图,就涉及到几个类,CodeStrategy则是策略模式,启动时将不同实例存储到map里,使用时从map获取实例,

CodeProcessAbstract为抽象类,除了共有方法在这里实现外,不同实现类不同规则则在此类进行抽象化方法,留给子类实现即可

GoodsCode以及OrderCode则是实现类,此只实现抽象类的抽象方法,用来处理不同规则处理,还是蛮简单的,大家可以仔细看下并对下代码

3.代码实现

3.1 模板模式

抽象类定义编码生成流程:

其中getCreateCode方法则是模板模式的体现,getPreCode是所有子类都可以使用的(因为根据不同类型查询码值),所以在此类里直接定义私有方式实现。

第二个是generateCode方法,这个方法在此类里只是定义抽象方法不实现,原因是每一个的子类实现是不一样的规则,所以这里交给具体子类实现即可。

第三个方法是updateNewCode,此方法也是所有子类共有可使用,所以在此类里实现即可,所有的都可以通过类型更新对应的新的码值即可,

public abstract class CodeProcessAbstract {

    // 模板模式处理流程
    public String getCreateCode(String codeType){
        // 获取前一个code码
        String preCode=getPreCode(codeType);
        // 根据旧编号生成新的编号
        String newCode=generateCode(preCode);
        // 将新的编号更新到库里
        updateNewCode(newCode,codeType);
        return newCode;
    }

    private String getPreCode(String codeType){
        // 假装从库里取出对应类型的code
        System.out.println("从库里取出码值:20230504001或1|"+codeType);
        return "20230504001";
    }

    protected abstract String generateCode(String preCode);


    private void updateNewCode(String newCode,String codeType){
        // 假装将新的编码入库
        System.out.println("将"+codeType+"更新code码为:"+newCode);

    }
}

 商品编号生成码类,继承 CodeProcessAbstract类,实现generateCode来生成新的编码,假如这个规则是年月日+序号,就需要将前一个编码值传入根据后几位序号+1

@Component
public class GoodsCode extends CodeProcessAbstract {
    @Override
    protected String generateCode(String preCode){
        // 模拟商品规则生成
        System.out.println("生成新的编号:20230504002");
        return "20230504002";
    }
}

序号生成码类,继承CodeProcessAbstract,实现自己的生成规则

@Component
public class OrderCode extends CodeProcessAbstract {
    @Override
    protected String generateCode(String preCode) {
        // 模拟序号生成编号
        System.out.println("生成新的编号:20230504002");
        return "2";
    }
}

还有别的一系列的子类,咱们先不一一介绍了,都是这样的方式。

这样执行流程我们定义完了,我们有了获取编码,生成编码,更新编码的能力,但是我们怎么去统一调用它呢,如果这个类用这个实现类,那个类用那个实现类,等到实现类一多是不是很混乱呢,对于用户来说更喜欢简洁的呀,所以这里我们用一个类来统一入口

3.2 策略模式

其实很简单,定义一个全局变量Map类型的用来存储各个子类实例的,子类实例采用Spring管理以及获取,然后在spring加载以后调用注册方法,则将两个子实例加载到map里,再用户使用时根据类型获取实例即可。

@Component
public class CodeStrategy {
  @Resource
  private  GoodsCode goodsCode;
  @Resource
  private  OrderCode orderCode;

  private final Map<String,CodeProcessAbstract> instanceMap=new HashMap(2);
  

  // 项目启动即可注册实例
  @PostConstruct
  public void register(){
     instanceMap.put(CodeTypeEnum.GOODS_NO.getCode(),goodsCode);
     instanceMap.put(CodeTypeEnum.ORDER_NO.getCode(),orderCode);
  }

  // 获取实例
  public CodeProcessAbstract getInstance(String codeType){
     return instanceMap.get(codeType);
  }
  
}

CodeTypeEnum枚举类

public enum CodeTypeEnum{
  GOODS_NO("goods_no","商品编号"),
  ORDER_NO("order_no","序号");

  private String code;
  private String name;

  private CodeTypeEnum(String code,String name){
    this.code=code;
    this.name=name;
  }
  public  String getCode(){
    return code;
  }

  public  String getName(){
    return name;
  }
}

4.使用

使用方式:单元测试如下

@SpringBootTest
public class TestStrategyMooban {

    @Resource
    private  CodeStrategy codeStrategy;

    @Test
    void useMS() {
        GoodsCode goods=(GoodsCode)codeStrategy.getInstance(CodeTypeEnum.GOODS_NO.getCode());
        String newCode=goods.getCreateCode(CodeTypeEnum.GOODS_NO.getCode());
        System.out.println("最终商品编号:"+newCode);

        OrderCode order=(OrderCode)codeStrategy.getInstance(CodeTypeEnum.ORDER_NO.getCode());
        String newCode1=order.getCreateCode(CodeTypeEnum.ORDER_NO.getCode());
        System.out.println("order序号编号:"+newCode1);
    }
}

 测试结果,我们可以看到只需要引用一个策略类即可调用不同的实例处理流程,每个流程都是一样的,只不过具体生成编码策略不同,这样代码是不是清晰了很多

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492344.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从供应链角度看进销存:区别与联系

供应链和进销存是两个紧密相关的概念&#xff0c;它们都涉及到企业在商品贸易中的运作过程。虽然它们有一些相似之处&#xff0c;但是它们也有一些显著的区别。本文将从几个方面探讨供应链和进销存的区别。 一、概念定义 供应链的定义&#xff1a;供应链是一系列的活动&#…

WPF 多媒体MediaElement 的使用(一)

本章讲述MediaElement的简单使用&#xff1a; WPF 中对于多媒体的支持非常完整&#xff0c;可以使用MediaElement 为应用程序添加媒体播放控件&#xff0c;以完成播放音频、视频功能。MediaElement 属于UIElement&#xff0c;同时也支持鼠标及键盘的操作。 想以交互方式停止、…

通达信N字形态选股公式,突破前期高点发出信号

行情经历一波上涨之后回调&#xff0c;然后再次上涨&#xff0c;形态类似于字母N&#xff0c;这就是N字形态。该形态在不同的分析方法中均有描述&#xff0c;如123法则、波浪理论等&#xff0c;只是名称不同而已。 本文的N字形态选股公式&#xff0c;以突破前期波段高点发出信号…

2023年留学基金委(CSC)青年骨干教师出国研修项目解读及建议

5月4日&#xff0c;国家留学基金委&#xff08;CSC&#xff09;公布了2023年青年骨干教师出国研修项目通知&#xff0c;知识人网小编现将其选派工作流程、选派办法、申请材料及说明原文转载并加以解读、提出建议。 知识人网解读及建议 一、2023年的通知精神与往年相比&#xf…

MySQL索引、事务与存储引擎

数据库索引 是一个排序的列表&#xff0c;存储着索引值和这个值对应的物理地址&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff08;类似于C语言的链表通过指针指向数据记录的内存地址&#xff09;无需对整个表进行扫描&#xff0c;而是先通…

C++图文安装教程,计算机零基础都能懂

系统&#xff1a;win11 软件&#xff1a;code blocks&#xff06;DEV-CPP 文章目录 一、Dev-Cpp安装步骤1.点击安装包2.选择我们的语言为English3.选择我同意即可4.点击next就可以&#xff0c;最后一个框除非是你之前有写过C的项目&#xff0c;想要清除&#xff0c;否则我们不用…

【Java|golang】2432. 处理用时最长的那个任务的员工

共有 n 位员工&#xff0c;每位员工都有一个从 0 到 n - 1 的唯一 id 。 给你一个二维整数数组 logs &#xff0c;其中 logs[i] [idi, leaveTimei] &#xff1a; idi 是处理第 i 个任务的员工的 id &#xff0c;且 leaveTimei 是员工完成第 i 个任务的时刻。所有 leaveTimei…

Android---启动速度优化

App 启动流程 1. 点击桌面 App 图标&#xff0c;Launcher 进程采用 Binder IPC 向 system_server 进程发起 startActivity 请求 &#xff1b; 2. system_server 进程接收到请求后&#xff0c;向 zygote 进程发送创建进程的请求&#xff1b; 3. zygote 进程 fork 出新的子进程…

KDGK-F断路器机械特性测试仪

一、产品概述 KDGK-F 断路器机械特性测试仪可用于各电压等级的真空、六氟化硫、少油、多油等电力系统高压开关的机械特性参数测试与测量。测量数据稳定&#xff0c;抗干扰性强&#xff0c;可在500KV等级及以下电站做实验&#xff0c;接线方便&#xff0c;操作简单&#xff0c;是…

TikTok选品要怎样才能选到爆品?!

对于做TikTok的商家而言&#xff0c;选品是非常重要的&#xff0c;因为一个产品爆了之后能带动其他产品的销量&#xff0c;那我们要如何有效的选品呢&#xff1f; 一、多平台选品逻辑 首先要知道一个点&#xff0c;在独立站爆的品也会在亚马逊爆&#xff0c;而TikTok已经成为一…

安卓Glide那些事情面试,一篇全部搞定

安卓Glide那些事情面试&#xff0c;一篇全部搞定 一.Glide有几级缓存&#xff1f;&#xff1f;&#xff1f;二.Gllide源码分析三.内存缓存和磁盘缓存LruCache算法四.Gllide基本使用五.Gllide高级使用:配置1.配置内存和磁盘缓存大小2.配置okhttp3.配置https认证4.使用 一.Glide有…

冲浪杂记——

华为od是指什么&#xff1f; 华为OD&#xff08;Open Developer Platform&#xff09;是华为面向全球开发者推出的开放平台&#xff0c;旨在为开发者提供丰富的技术资源和开发工具&#xff0c;支持开发者快速构建基于华为技术的应用程序、解决方案和服务。华为OD平台为开发者提…

微软新Bing全面开放BingChat,无需排队,直接用

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 好消息&#xff0c;所有人都能上手微软Bing了!微软表示&#xff0c;为了感谢大量用户的使用与反馈&#xff0c;从今天起新 Bing 不再有候补名单&#xff0c;只要使用微软账户登录 Bing&#xff0c;…

函数(1)

文章目录 目录1. 函数是什么2. 库函数3. 自定义函数4. 函数的参数4.1 实际参数&#xff08;实参&#xff09;4.2 形式参数&#xff08;形参&#xff09; 5. 函数的调用5.1 传值调用5.2 传址调用5.3 练习 附&#xff1a; 目录 函数是什么库函数自定义函数函数的参数函数的调用函…

实现北大官网首页的动态图标

逛网站的时候&#xff0c;看见有人在问如何实现北大官网的动态图标&#xff0c;因为做过类似的东西&#xff0c;所以想把这个方法整理下来。 点上去会有一个小动画的那种。 如何实现该图标的动态效果 一句话&#xff1a;用svg实现图标&#xff0c;利用stroke-dasharray和str…

Rust - 切片Slice

Slice类型 Slice数据类型没有所有权&#xff0c;slice允许我们引用集合中一段连续的元素序列而不用引用整个集合。字符串slice(string slice) 是String中 一部分值的引用。如下述代码示例&#xff0c;不是对整个String的引用而是对部分String的引用&#xff1a; fn main() {l…

虹科方案 | HK-Edgility面向未来的安全 SD-WAN

通过上期的文章&#xff0c;我们了解到虹科HK-Edgility软件系统《随时随地保护您的远程工作解决方案》的解决方案。这篇文章&#xff0c;我们将带您了解虹科系统在SD-WAN的方案简介。 一、时代背景 过去&#xff0c;企业使用专线或MPLS解决方案将其站点和办公室连接到企业数据中…

数据结构——链表(python版)

一、链表简介 链表是一种在存储单元上非连续、非顺序的存储结构。数据元素的逻辑顺序是通过链表中的指针链接次序实现。链表是由一系列的结点组成&#xff0c;结点可以在运行时动态生成。每个结点包含两部分&#xff1a;数据域与指针域。数据域存储数据元素&#xff0c;指针域…

封装server类,创建多个server服务

&#xff08;一&#xff09;封装server类 MessageHeader.hpp #ifndef _MessageHeader_hpp_ #define _MessageHeader_hpp_ #endif #pragma once enum CMD {CMD_LOGIN,CMD_LOGIN_RESULT,CMD_LOGOUT,CMD_LOGOUT_RESULT,CMD_NEW_USER_JOIN,CMD_ERROR };struct DataHeader {short …

安装RedisBloom插件

前言 安装RedisBloom模块会遇到很多坑&#xff0c;希望你不要和我一样踩的这么全&#x1f60f;。 下载RedisBloom插件 布隆过滤器插件下载地址 github.com/RedisBloom/RedisBloom/releases 在对应的Linux机器下载 wget https://github.com/RedisBloom/RedisBloom/archive/…