设计模式之模板方法

news2024/11/16 10:48:51

一、概述

定义一个操作中的算法的骨架,将一些步骤延迟到子类中。 TemplateMethod使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。

二、适用性

1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。 首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。 最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

3.控制子类扩展。

三、参与者

1.AbstractClass 定义抽象的原语操作(primitive operation),具体的子类将重新定义它们以实现一个算法的各个步骤。 实现一个模板方法,定义一个算法的骨架。 该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作。

2.ConcreteClass 实现原语操作以完成算法中与特定子类相关的步骤。

四、类图

五、示例

AbstractClass

public abstract class Template {
    public abstract void print();
    public void update() {
        System.out.println("开始打印");
        for (int i = 0; i < 10; i++) {
            print();
        }
    }
}

ConcreteClass

public class TemplateConcrete extends Template{
    @Override
    public void print() {
        System.out.println("这是子类的实现");
    }
}

自测

@Test
public void testTemplate() {
   Template temp = new TemplateConcrete();
   temp.update();
}

自测结果

Connected to the target VM, address: '127.0.0.1:12824', transport: 'socket'
开始打印
这是TemplateConcrete类的实现
这是TemplateConcrete类的实现
这是TemplateConcrete类的实现
Disconnected from the target VM, address: '127.0.0.1:12824', transport: 'socket'

六、实践

封装

/**
 * @author lyonardo
 * @Description
 * @createTime 2022年09月20日 13:52:00
 */@Slf4j
public abstract class FxBaseExtServiceAbstract<T, E> {
    private final AccessTokenServcie accessTokenServcie = SpringUtil.getBean(AccessTokenServcie.class);
   /* private final MongoService mongoService = SpringUtil.getBean(MongoService.class);
    public List<E> pick(Class<E> var2) {
        return mongoService.find(new Query(), var2);
    }*/
    public List<E> pickFx(String dataObjectApiName, List<Filter> filterList, String url, Class<E> var2) {
        Assert.notNull(accessTokenServcie,"没有获取到纷享token");
        //获取接口授权token
        FxiaokeAccessToken fxiaokeAccessToken = accessTokenServcie.getAccessToken();
        Assert.notNull(fxiaokeAccessToken,"没有获取到纷享token");
        List<E> all = new ArrayList<>();
        long startTime = System.currentTimeMillis();
        String dataId = "";
        for (; ; ) {
            List<Filter> filters = new ArrayList<>(filterList);
            filters.add(new Filter("_id", Lists.newArrayList(dataId), "GT"));
            List<Order> orderList = new ArrayList<>();
            orderList.add(new Order("_id", true));
            //组装接口入参
            FxiaokeBaseReq map = FxiaokeUtil.buildParamMapExt(dataObjectApiName, null, filters, orderList, fxiaokeAccessToken, accessTokenServcie.getCurrentOpenUserId());
            //入参转换json
            String jsonString = JSON.toJSONString(map);
            log.info("数据处理同步纷享接口入参=>{}", jsonString);
            //调用纷享预设对象(属性对象)API
            String result = OsHttpClient.create().post(url, jsonString);
            String dataListString = FxiaokeUtil.handleResponseResult(result);
            if (!StringUtils.hasText(dataListString)) {
                break;
            }
            JSONArray isExit = JSON.parseArray(dataListString);
            if (isExit.isEmpty()) {
                break;
            }

            JSONObject jsonObject = JSONObject.parseObject(isExit.get(isExit.size() - 1).toString());
            if (jsonObject.isEmpty()) {
                break;
            }
            if (all.size()> 2000) {
                break;
            }
            dataId = jsonObject.getString("_id");
            log.info("dataId=>>>{}", dataId);
            all.addAll(JSON.parseArray(dataListString, var2));
        }
        long endTime = System.currentTimeMillis();
        long totalTime = (endTime - startTime) / 1000;
        log.info("请求接口全量数据耗时=>>>{}秒", totalTime);
        return all;
    }

    /**
     * @param resourceList 源list
     * @description list转换器 List<E> -> List<T>
     * @datetime 2022-09-20 16:31:04
     */
    protected abstract List<T> getListConverter(List<E> resourceList);

    public void handle(List<T> list, IService<T> iService) {
        long start = System.currentTimeMillis();
        iService.remove(new QueryWrapper<T>().eq("ITEM_DATA_FROM", DataFromEnum.FXIAOKE.getCode()));
        iService.saveOrUpdateBatch(list);
        long end = System.currentTimeMillis();
        log.info("全量数据处理同步耗时:=>{}秒", (end - start)/ 1000);
    }

    public void incrHandle(List<T> list, IService<T> iService) {
        long start = System.currentTimeMillis();

        iService.saveOrUpdateBatch(list);

        long end = System.currentTimeMillis();
        log.info("增量据处理同步耗时:=>{}", (end - start));
    }

    /**
     * @param type     1  天翎业务表id是纷享的;2 天翎业务表id是天翎的
     * @param dataId
     * @param list
     * @param iService
     * @description
     * @datetime 2022-09-22 20:50:44
     */
    public void incrHandlePlus(Integer type, String dataId, Wrapper<T> queryWrapper, List<T> list, IService<T> iService) {
        long start = System.currentTimeMillis();

        if (1 == type) {
            iService.removeById(dataId);
        } else {
            iService.remove(queryWrapper);
        }
        iService.saveOrUpdateBatch(list);
        long end = System.currentTimeMillis();
        log.info("增量数据处理同步耗时:=>{}秒", (end - start) / 1000);
    }

    public void dataHandle(String dataObjectApiName, Integer type, List<Filter> filterList, String dataId,
                           String url, Wrapper<T> queryWrapper, IService<T> iService, Class<E> var2) {
        if (CollectionUtils.isEmpty(filterList) && !StringUtils.hasText(dataId)) {
            filterList = Arrays.asList(
                    new Filter("is_deleted", Collections.singletonList(Boolean.FALSE), "EQ"),
                    new Filter("life_status", Collections.singletonList("normal"), "EQ")
            );
        }
        if (StringUtils.hasText(dataId)) {
            filterList.add(new Filter("_id", Lists.newArrayList(dataId), "EQ"));
        }
        //请求解析出参
        List<E> resourceList = this.pickFx(dataObjectApiName, filterList, url, var2);
        //打印一条数据
        log.info("list size ==> {}\n,   resourceList ==>\n {}", resourceList.size(), JSON.toJSONString(Optional.of(resourceList).map(t -> t.get(0)).orElse((E) "")));

        if (StringUtils.hasText(dataId)) {
            this.incrHandlePlus(type, dataId, queryWrapper, getListConverter(resourceList), iService);
        } else {
            this.handle(getListConverter(resourceList), iService);
            this.getListConverterFinall(resourceList);
        }
    }

    protected abstract void getListConverterFinall(List<E> resourceList);

}

使用

/**
 * @author lyonardo
 * @Description 客户监听订阅事件
 * @createTime 2022年09月20日 09:38:00
 */
@Slf4j
@Service
public class FxAccountListener extends FxBaseListenerAbstract<TlkAccountInfoDO, FxAccountObjBO> {
    private final ITlkAccountInfoService service = SpringUtil.getBean(ITlkAccountInfoService.class);

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void handle(String eventType, String dataId) {
        if (EventTypeConstants.UPDATE.equals(eventType) || EventTypeConstants.INSERT.equals(eventType)) {
            //请求解析出参
            LambdaUpdateWrapper<TlkAccountInfoDO> updateWrapper = new LambdaUpdateWrapper<TlkAccountInfoDO>().eq(TlkAccountInfoDO::getItemThirdId, dataId);
            this.dataHandle(DataObjectApiNameConstants.ACCOUNTOBJ, dataId, FxCommonEnum.GET.buildUrl(), service, updateWrapper, FxAccountObjBO.class);
        } else if ( EventTypeConstants.INVALID.equals(eventType) || EventTypeConstants.DELETE.equals(eventType)) {
            service.remove(new LambdaQueryWrapper<TlkAccountInfoDO>().eq(TlkAccountInfoDO::getItemThirdId, dataId));
        } else {
            throw new OsRuntimeException(FailCodeEnum.FAIL);
        }
    }

    @Override
    protected TlkAccountInfoDO getConverter(FxAccountObjBO resource) {
        TlkAccountInfoDO tlkAccountInfoDO = TlkAccountInfoDOConverter.INSTANCE.fxAccountObjBo2Do(resource);
        String mark = CustomerLevelEnum.getMarkByCode(tlkAccountInfoDO.getItemCustomerLevelCode());
        if(StringUtils.isNotEmpty(mark)){
            tlkAccountInfoDO.setItemCustomerLevelName(mark);
        }else if("".equals(mark)){
            tlkAccountInfoDO.setItemCustomerLevelCode(CustomerLevelEnum.MSTSC.getCode());
            tlkAccountInfoDO.setItemCustomerLevelName(CustomerLevelEnum.MSTSC.getDescription());
        }else {
            tlkAccountInfoDO.setItemCustomerLevelCode("cooperation_price");
            tlkAccountInfoDO.setItemCustomerLevelName("项目合作价");
        }
        return tlkAccountInfoDO;
    }
}

通过对核心方法的抽取处理以及公共抽象方法的封装,让团队其他开发在进行几十上百个业务对象进行全量、增量、对接开发时,只需要关注和实现业务对象的handle方法和对象转换处理getConverter,不用关注具体的细节,不仅大大减少了代码重复量和工作量,也大大降低了易错率。

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

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

相关文章

数据库与数据仓库的区别及关系

数据库与数据仓库的区别及关系 数据库数据仓库异同差异联系例子 数据库 数据库是结构化信息或数据的有序集合&#xff0c;一般以电子形式存储在计算机系统中。通常由数据库管理系统 (DBMS) 来控制。它是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集…

vue v-slot指令

目录 定义语法使用场景场景一场景二场景三tips只有一个默认插槽时 定义 在Vue中&#xff0c; v-slot 指令用于定义插槽的模板内容。它用于在父组件中传递内容到子组件中的插槽。 v-slot 指令可以用于 标签或组件标签上&#xff0c;以便在子组件中使用插槽。 语法 使用 v-slo…

记录--基于css3写出的流光登录(注释超详细!)

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 完整效果 对基本的表单样式进行设置 这里设置了基本的表单样式&#xff0c;外层用了div进行包裹&#xff0c;重点是运用了两个i元素在后期通过css样式勾画出一条线没在聚焦文本框的时候线会过度成一个…

【Spring框架】Spring事务

目录 Spring中事务的实现编程式事务声明式事务Transactional 作⽤范围Transactional 参数说明注意事项Transactional ⼯作原理 MySQL 事务隔离级别Spring 事务隔离级别事务传播机制 Spring中事务的实现 Spring中事务操作分为两类&#xff1a; 1.编程式事务 2.声明式事务 编程…

c语言小知识点

文章目录 int main()与int main(void)符号常量常变量无符号赋值将占字节多的赋值给字节少的类型赋初值 表达式预处理格式符e格式符 循环for 输入长度相关输出文件管理 int main()与int main(void) int main(void) 指的是此函数的参数为空&#xff0c;不能传入参数&#xff0c;…

Streamlit的第一个应用(二)

文章目录 1 前言2 创建第一个应用 &#x1f4dd;&#x1f680;3 获取数据 &#x1f4e6;&#x1f50d;4 函数缓存&#x1f680;&#x1f50d;&#x1f4ca;5 赏析原始数据 ✨&#x1f389;6 绘制直方图 &#x1f4ca;✨7 所有乘车点的地图 &#x1f30d;&#x1f696;8 完整代码…

Linux修改系统语言

sudo dpkg-reconfigure locales 按pagedown键&#xff0c;移动红色光标到 zh_CN.UTF-8 UTF-8&#xff0c;空格标记*号&#xff08;没标记下一页没有这一项&#xff09;&#xff0c;回车。 下一页选择 zh_CN.UTF-8。 如果找不到 dpkg-reconfigure whereis dpkg-reconfigure …

手机变电脑2023之虚拟电脑droidvm

手机这么大的内存&#xff0c;装个app来模拟linux&#xff0c;还是没问题的。 app 装好后&#xff0c;手指点几下确定按钮&#xff0c;等几分钟就能把linux桌面环境安装好。 不需要敲指令&#xff0c; 不需要对手机刷机&#xff0c; 不需要特殊权限&#xff0c; 不需要找驱…

第二十二章 原理篇:UP-DETR

最近一直在忙各种各样的面试&#xff0c;顺便重新刷了一遍西瓜书。 感觉自己快八股成精了&#xff0c;但是一到写代码的环节就拉跨&#xff0c;人真是麻了。 许愿搬家前可以拿到offer&#xff01; 参考教程&#xff1a; https://arxiv.org/pdf/2011.09094.pdf https://zhuanla…

第一百二十二天学习记录:C++提高:STL-vector容器(上)(黑马教学视频)

vector基本概念 功能&#xff1a; vector数据结构和数组非常相似&#xff0c;也称为单端数组 vector与普通数组区别&#xff1a; 不同之处在于数组是静态空间&#xff0c;而vector可以动态扩展 动态扩展&#xff1a; 并不是在原空间之后续接新的空间&#xff0c;而是找更大的内…

荐读 | 《揭秘云计算与大数据》

当我们回顾过去几十年的科技进步时&#xff0c;云计算和大数据在现代科技发展史上无疑具有里程碑式的意义&#xff0c;它们不仅改变了我们的生活方式&#xff0c;而且对各行各业产生了深远的影响。 在这个数字化时代&#xff0c;云计算和大数据技术已经成为推动全球发展的关键…

Java:如何破坏类加载器的双亲委派机制?

本文重点 我们前面分析过loadClass方法,我们可以发现,这个方法的逻辑就是双亲委派机制,也就是说只要不破坏这个方法,那么就不会破坏双亲委派机制。如果要想破坏双亲委派机制,我们需要在类中重写loadClass方法,只要这样,那么就不会走双亲委派机制了。 破坏还是不破坏双…

【GitOps系列】使用 ArgoCD ApplicationSet 来实现多环境管理

文章目录 前言自动多环境管理概述自动化管理多环境实战示例应用简介ApplicationSet 简介部署 ApplicationSet访问多环境 创建新环境实验结语 前言 聊起多环境&#xff0c;通常可能会立即想到下面几个常见的环境&#xff1a; 开发环境测试环境预发布环境生产环境 为了让不同职…

TikTok运营五个要点,这些你都知道吗?

TikTok也就是海外版抖音&#xff0c;和抖音一样同属于字节跳动&#xff0c;其整个发展模式也类似于抖音&#xff0c;但相比抖音现在成熟的商业模式而言&#xff0c;TikTok还处于明显的娱乐阶段&#xff0c;虽然它也在缓慢的测试一些电商。 即使如此&#xff0c;由于抖音的巨大…

group normalization

1、 Theory look for this link for more information, actually only this image can illustrate the group normalization.you can ignore the rest of this artical. 2、 Code check this link for detailed about the formulation and the theory of the group normalzi…

基于 yolov8 的人体姿态评估

写在前面 工作中遇到&#xff0c;简单整理博文内容为使用预训练模型的一个预测 Demo测试图片来源与网络,如有侵权请告知理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停…

软考A计划-系统集成项目管理工程师-信息系统安全管理-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

从excel中提取嵌入式图片的解决方法

1 发现问题 我的excel中有浮动图片和嵌入式图片&#xff0c;但是openpyxl的_image对象只提取到了浮动图片&#xff0c;通过阅读其源码发现&#xff0c;这是因为openpyxl只解析了drawing文件导致的&#xff0c;所以确定需要自己解析 2 解决思路 1、解析出media资源 2、解析…

阿里云“通义千问”开源,可免费商用

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 阿里云成为国内首个加入大模型开源行列的大型科技企业。就在昨天&#xff0c;阿里云公开表态&#xff0c;把自家的通义千问大模型开源。 阿里云把通用70亿参数模型&#xff0c;包括Qwen-7B和对话模…

python 变量赋值 修改之后 原值改变

ython 是一种动态语言&#xff0c;因此变量的类型和值 在运行时均可改变。当我们将一个变量赋值给另一个变量时&#xff0c;实际上是将变量的引用地址传递给新的变量&#xff0c;这意 味着新旧变量将指向同一个位置。因此&#xff0c;在更改其中一个变量的值时&#xff0c;另一…