设计模式之模板方法

一、概述

定义一个操作中的算法的骨架,将一些步骤延迟到子类中。 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{@Overridepublic 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");//获取接口授权tokenFxiaokeAccessToken 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());//入参转换jsonString jsonString = JSON.toJSONString(map);log.info("数据处理同步纷享接口入参=>{}", jsonString);//调用纷享预设对象(属性对象)APIString 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);}}@Overrideprotected 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.mzph.cn/news/23586.shtml

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

相关文章

Java课题笔记~ MyBatis接口开发(代理开发)

使用XML文件进行开发&#xff0c;在调用SqlSession进行操作时&#xff0c;需要指定MyBatis映射文件中的方法&#xff0c;这种调用方式过于烦琐。为解决此问题&#xff0c;MyBatis提供了接口开发的方式。 接口开发的目的&#xff1a; 解决原生方式中的硬编码 简化后期执行SQL …

nacos本地搭建+springCloud服务注册中心-nacos(简易实现)

一.nacos概述 nacos官网 二.Windows使用搭建nacos 较为完整使用参考 1.安装nacos 去nacos github下载nacos最新稳定版本&#xff0c;我用的是nacos-server-2.2.3.zip&#xff0c;下载后解压&#xff0c;得到 2.创建数据库 启动mysql&#xff0c;创建数据库nacos&#xff…

掌握 JVM 的参数及配置

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ JVM&#xff08;Java虚拟机&#xff09;是Java编程语言的核心组件之一&#xff0c;它负责执行Java程序&#xff0c;并提供一系列参数和配置选项&#xff0c;可以调整Java程…

Docker实战-操作Docker容器实战(一)

导语   在之前的分享中&#xff0c;我们介绍了关于如何去操作Docker镜像&#xff0c;下面我们来看看如何去操作容器。 简单来讲&#xff0c;容器是镜像运行的一个实例&#xff0c;与镜像不同的是镜像只能作为一个静态文件进行读取&#xff0c;而容器是可以在运行时进行写入操…

docker端口映射详解(随机端口、指定IP端口、随意ip指定端口、指定ip随机端口)

目录 docker端口映射详解 一、端口映射概述&#xff1a; 二、案例实验&#xff1a; 1、-P选项&#xff0c;随机端口 2、使用-p可以指定要映射到的本地端口。 Local_Port:Container_Port&#xff0c;任意地址的指定端口 Local_IP:Local_Port:Container_Port 映射到指定地…

Docker安装Grafana以及Grafana应用

Doker基础 安装 1、 卸载旧的版本 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 2、需要的安装包 sudo yum install -y yum-utils 3、设置镜像的仓库 yum-config-m…

Spring Boot 单元测试

目录 1.什么是单元测试&#xff1f; 2.单元测试的优点 3.Spring Boot 单元测试使用 3.1 生成单元测试的类 3.2 添加 Spring Boot 框架测试注解&#xff1a;SpringBootTest 3.3 添加单元测试业务逻辑 3.4 注解 Transactional 4. 断言 1.什么是单元测试&#xff1f; 单元…

39.利用matlab寻找素数(matlab程序)

1.简述 MATLAB嵌套循环允许使用一个循环在另一循环内&#xff0c;下面用一个嵌套循环来把所有从1到100的素数显示出来。 2.代码 %% 学习目标&#xff1a;寻找素数 clear sum5; %求0&#xff5e;100素数之和 ss0; %用来标定是否是素数&#xff0c;0表示不是 p…

C#使用EmguCV播放视频

目录 一、前言 1、简介 2、测试工程代码下载链接 3、EmguCV 库文件下载链接 二、工程环境配置 1、EmguCV控件添加引用 &#xff08;1&#xff09;窗口控件添加 &#xff08;2&#xff09;相关Dll文件添加添加引用 &#xff08;3&#xff09;工程运行基础文件夹添加 &a…

CVS,SVN,Git,Mercurial 代码管理工具

现代软件开发过程中要实现高效的团队协作&#xff0c;需要使用代码分支管理工具实现代码的共享、追溯、回滚及维护等功能。目前流行的代码管理工具&#xff0c;包括 CVS&#xff0c;SVN&#xff0c;Git&#xff0c;Mercurial 等 CVS 和 SVN 是集中管理&#xff0c;Git 具有非常…

解决github打不开的方法

解决github打不开的方法 本文参考文章&#xff1a;解决可ping通但无法访问github网站的问题 一、确定域名github.com的ip地址 进入网址 IP/服务器github.com的信息 - 站长工具 (chinaz.com)&#xff0c;查看 ip 地址。 20.205.243.166 github.com二、确定域名github.global.…

使用ubuntu-base制作根文件系统

1&#xff1a;ubuntu官网下载最小根文件系统&#xff1a; 放置到电脑的ubuntu中&#xff0c; Mkdir Ubuntu_rootfs Cd Ubuntu_rootfs Sudo tar –zxvf Ubuntu-bash-xxxxxx.tar.gz 2&#xff1a;电脑的ubuntu安装qemu搭建arm模拟系统 将/usr/bin/qemu-arm-static/(64位拷贝…

Milvus Cloud凭借AI原生,可视化优势荣登全球向量数据库性能排行榜VectorDBBench.com 榜首

在当今的大数据时代,随着人工智能技术的快速发展,向量数据库作为处理大规模数据的关键工具,其性能和效率越来越受到关注。最近,全球向量数据库性能排行榜 VectorDBBench.com 公布了一份最新的评估报告,引人瞩目的是,成立不到一年的新兴公司 Milvus Cloud 凭借其 AI 原生和…

LNMP及论坛搭建

安装 Nginx 服务 systemctl stop firewalld systemctl disable firewalld setenforce 0 1.安装依赖包 #nginx的配置及运行需要pcre、zlib等软件包的支持&#xff0c;因此需要安装这些软件的开发包&#xff0c;以便提供相应的库和头文件。 yum -y install pcre-devel zlib-devel…

抖音seo源码开发源代码搭建分享

抖音SEO源码开发涉及到以下几个方面&#xff1a; 前端开发&#xff1a;包括抖音SEO页面的设计与布局&#xff0c;以及需要使用到的前端技术&#xff0c;如HTML、CSS、JavaScript等。 后端开发&#xff1a;包括抖音SEO页面的数据获取和处理&#xff0c;以及需要使用到的后端技术…

JavaScript数据结构与算法——栈

文章目录 一、初始栈结构1.1 特性1.2 注意事项 二、栈结构的封装2.1 封装简单栈结构2.2 利用栈将十进制转二进制 一、初始栈结构 1.1 特性 类似于汉诺塔&#xff0c;后进先出&#xff0c;每次只能操作栈顶的元素。关键词&#xff1a;压栈、退栈 简单示意图&#xff1a; 1.…

python-面向对象.多态

多态 多态 什么是多态&#xff1a; 定义时的类型和运行时的类型不一样&#xff0c;也就是定义时并不确定要调用的是 哪个方法&#xff0c; 只有运行的时候才能确定调用的是哪个 多态特性 多态性是指在不考虑实例类型的情况下使用实例&#xff0c; 多态性分为静态多态性和动态…

LLM - LLama 模型读取报错 TypeError: not a string

一.引言 读取 LLama2 模型时报错 TypeError: not a string 看异常栈是 AutoTokenizer.from_pretrained 时候的异常。 二.问题解决 出现类似加载模型异常的问题&#xff0c;大致分两类&#xff1a; ◆ 模型地址异常 脚本里传的 pretrained_model Path 有问题&#xff0c;加 …

Eureka 学习笔记5:InstanceRegistry

版本 awsVersion ‘1.11.277’ LeaseManager 接口管理实例的租约信息&#xff0c;提供以下功能&#xff1a; 注册实例取消注册实例实例续约剔除过期实例 public interface LeaseManager<T> {/** 注册实例并续约*/void register(T r, int leaseDuration, boolean isRep…

socket server服务器开发常见的并发模型

两种高效的事件处理模式 服务器程序通常需要处理三类事件&#xff1a;I/O 事件、信号及定时事件。有两种高效的事件处理模式&#xff1a;Reactor和 Proactor&#xff0c;同步 I/O 模型通常用于实现Reactor 模式&#xff0c;异步 I/O 模型通常用于实现 Proactor 模式。 无论是 …