设计模式之模板方法

一、概述

定义一个操作中的算法的骨架,将一些步骤延迟到子类中。 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 < 3; i++) {
            print();
        }
    }
}

ConcreteClass

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

自测

@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 纷享事件变更订阅处理基类:纷享事件变更返回值有书大局id,通过id查询详情;根据变更事件类型,天翎进行相应操作
 * @createTime 2022年09月24日 14:35:00
 */
@Slf4j
public abstract class FxBaseListenerAbstract<T, E> {
    private final AccessTokenServcie accessTokenServcie = SpringUtil.getBean(AccessTokenServcie.class);

   /* private final MongoService mongoService = SpringUtil.getBean(MongoService.class);
    public E pick(String dataId, Class<E> var2){
        return mongoService.findById(dataId,var2);
    }*/

    public E pickFx(BaseObjectDataBO baseObjectDataBO, String url, Class<E> var2){
        String detalString = pickFxResult(baseObjectDataBO,url);
        return JSON.parseObject(detalString, var2);
    }

    protected abstract T getConverter(E resource);

    public void dataHandle(String dataObjectApiName, String dataId , String url, IService<T> iService, LambdaUpdateWrapper<T> updateWrapper, Class<E> var2){
        GetDetailObjectDataBO getDetailObjectDataBO = buildGetDetailObjectDataBO(dataObjectApiName, dataId);
        E fxObjBO = this.pickFx(getDetailObjectDataBO, url, var2);
        if(Objects.nonNull(fxObjBO)){
            T tlkObjDO = getConverter(fxObjBO);
            log.info("FxBaseListenerAbstract==>dataHandle getConverter对象转换结果tlkObjDO=>{}", JSON.toJSONString(tlkObjDO));
            if(Objects.nonNull(tlkObjDO)){
                iService.saveOrUpdate(tlkObjDO, updateWrapper);
            }else {
                log.warn("FxBaseListenerAbstract==>dataHandle getConverter对象转换出现异常");
            }
        }else {
            log.warn("FxBaseListenerAbstract==>dataHandle没有pickFx到纷享对象数据");
        }
    }

 public String pickFxResult(BaseObjectDataBO baseObjectDataBO, String url){
        Assert.notNull(accessTokenServcie,"没有获取到纷享token");
        //获取接口授权token
        FxiaokeAccessToken fxiaokeAccessToken = accessTokenServcie.getAccessToken();
        Assert.notNull(fxiaokeAccessToken,"没有获取到纷享token");
        //组装接口入参
        FxiaokeApiReqBO fxiaokeApiReqBO = FxiaokeUtil.buildInvalidOrGetParam(fxiaokeAccessToken, accessTokenServcie.getCurrentOpenUserId(), baseObjectDataBO);
        //入参转换json
        String jsonString = JSON.toJSONString(fxiaokeApiReqBO);
        log.info("数据处理同步纷享接口入参=>{}", jsonString);
        //调用纷享预设对象(属性对象)API 噢易HttpClient
        String result = OsHttpClient.create().post(url, jsonString);
        return FxiaokeUtil.handleResponseResult(result);
    }
}

使用

/**
 * @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,不用关注具体的细节,不仅大大减少了代码重复量和工作量,也大大降低了易错率。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv5修改注意力机制CBAM

直接上干货 CBAM注意力机制是由通道注意力机制&#xff08;channel&#xff09;和空间注意力机制&#xff08;spatial&#xff09;组成。 传统基于卷积神经网络的注意力机制更多的是关注对通道域的分析&#xff0c;局限于考虑特征图通道之间的作用关系。CBAM从 channel 和 sp…

Kafka与Zookeeper版本对应关系

文章目录 了解版本对应Kafka安装包Kafka源码包 了解 比如&#xff1a; kafka_2.11-1.1.1.jar包 其中2.11表示的是Scala的版本&#xff0c;因为Kafka服务器端代码完全由Scala语音编写。”-“后面的1.1.1表示的kafka的版本信息。遵循一个基本原则&#xff0c;Kafka客户端版本和服…

MySQL5.7数据库、Navicat Premium1.6可视化工具安装教程【详细教程】

文章目录 一、MySQL、Navicat、注册机地址二、安装&#xff08;一&#xff09;、MySQL安装&#xff08;二&#xff09;、Navicat Premium安装&#xff08;三&#xff09;、集活Navicat Premium 三、遇到的问题1、Are you sure your navicat has not beenpatched/modified befor…

Spring 事务管理

目录 1. 事务管理 1.1. Spring框架的事务支持模型的优势 1.1.1. 全局事务 1.1.2. 本地事务 1.1.3. Spring框架的一致化编程模型 1.2. 了解Spring框架的事务抽象&#xff08;Transaction Abstraction&#xff09; 1.2.1. Hibernate 事务设置 1.3. 用事务同步资源 1.3.1…

Malloc动态内存分配

在C语言中我们会使用malloc来动态地分配内存&#xff0c;这样做的一个主要理由是有些数据结构的大小只有在运行时才能确定。例如&#xff0c;如果你正在编写一个程序&#xff0c;需要用户输入一些数据&#xff0c;但你不知道用户会输入多少数据&#xff0c;那么你就需要使用动态…

vue3使用pinia和pinia-plugin-persist做持久化存储

1、安装依赖 pnpm i pinia // 安装 pinia pnpm i pinia-plugin-persist // 安装持久化存储插件2、main.js引入 import App from ./App.vue const app createApp(App)//pinia import { createPinia } from pinia import piniaPersist from pinia-plugin-persist //持久化插件 …

Python中enumerate用法详解

目录 1.简介 2.语法 3.参数 4.返回值 5.详解 6.实例 7.补充 1.简介 enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列&#xff0c;同时列出数据和数据下标&#xff0c;一般用在 for 循环当中。 2.语法 以下是 enumerate() 方法的语…

Qt应用开发(基础篇)——堆栈窗口 QStackedWidget

一、前言 QStackedWidget继承于QFrame&#xff0c;QFrame继承于QWidget&#xff0c;是Qt常用的堆栈窗口部件。 框架类QFrame介绍 QStackedWidget堆栈窗口&#xff0c;根据下标切换&#xff0c;一次显示一个小部件&#xff0c;常用于应用界面切换、图片轮询播放等场景。 二、QSt…

通义千问开源模型部署使用

首先可以参考modelScope社区给出的使用文档&#xff0c;已经足够全面 通义千问-7B-Chat 但在按照文档中步骤部署时&#xff0c;还是有些错误问题发生&#xff0c;可以搜索参考的解决方式不多&#xff0c;所以记录下来 个人电脑部署 这里不太建议使用自己的笔记本部署通义千…

exchange partition global index

EXCHANGE PARTITION with a Table having a UNIQUE INDEX and PK Constraint. (Doc ID 1620636.1)​编辑To Bottom In this Document Symptoms Changes Cause Solution References APPLIES TO: Oracle Database - Enterprise Edition - Version 11.2.0.3 and later Oracle Da…

Spring整合MyBatis(详细步骤)

Spring与Mybatis的整合&#xff0c;大体需要做两件事&#xff0c; 第一件事是:Spring要管理MyBatis中的SqlSessionFactory 第二件事是:Spring要管理Mapper接口的扫描 具体的步骤为: 步骤1:项目中导入整合需要的jar包 <dependency><!--Spring操作数据库需要该jar包…

gazebo 导入从blender导出的dae等文件

背景&#xff1a; gazebo 模型库里的模型在我需要完成的任务中不够用&#xff0c;还是得从 solidworks、3DMax, blender这种建模软件里面在手动画一些&#xff0c;或者去他们的库里面在挖一挖。 目录 1 blender 1-1 blender 相关links 1-2 install 2 gazebo导入模型 2-1 g…

湘大 XTU OJ 1308 比赛 题解:循环结束的临界点+朴素模拟

一、链接 比赛 二、题目 题目描述 有n个人要进行比赛&#xff0c;比赛规则如下&#xff1a; 假设每轮比赛的人是m&#xff0c;取最大的k&#xff0c;k2^t且k≤m。这k个人每2人举行一场比赛&#xff0c;胜利者进入一下轮&#xff0c;失败者被淘汰。余下的m-k个人&#xff0…

从Spring源码看创建对象的过程

从Spring源码看创建对象的过程 Spring对于程序员set注入的属性叫做属性的填充、对于set注入之后的处理&#xff08;包括BeanPostProcessor的处理、初始化方法的处理&#xff09;叫做初始化。 研读AbstractBeanFactory类中的doGetBean()方法 doGetBean()方法首先完成的工作是…

mysql基础之触发器的简单使用

1.建立学生信息表 -- 触发器 -- 建立学生信息表 create table s1(id int unsigned auto_increment,name varchar(30),score tinyint unsigned,dept varchar(50),primary key(id) );2.建立学生补考信息表 -- 建立学生补考信息表 create table s2 like s1;3.建立触发器&#xf…

Grafana技术文档-概念-《十分钟扫盲》

Grafana官网链接 Grafana: The open observability platform | Grafana Labs 基本概念 Grafana是一个开源的度量分析和可视化套件&#xff0c;常用于对大量数据进行实时分析和可视化。以下是Grafana的基本概念&#xff1a; 数据源&#xff08;Data Source&#xff09;&#…

【大数据】Flink 详解(一):基础篇

Flink 详解&#xff08;一&#xff09;&#xff1a;基础篇 1、什么是 Flink &#xff1f; Flink 是一个以 流 为核心的高可用、高性能的分布式计算引擎。具备 流批一体&#xff0c;高吞吐、低延迟&#xff0c;容错能力&#xff0c;大规模复杂计算等特点&#xff0c;在数据流上提…

模板的进阶

目录 1.非类型模板参数 2.模板特化 2.1概念 2.2函数模板特化 2.3类模板特化 2.3.1全特化 2.3.2偏特化 3.模板分离编译 3.1什么是分离编译 3.2 模板的分离编译 3.3解决方法 4. 模板总结 1.非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a…

Python(七十五--总结)列表、字典、元组、集合总结

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

关于Object 0 = new Object() 的追魂九连问

文章目录 对象的创建过程对象的组成解析普通对象**结果分析&#xff1a;**给对象添加属性注意事项 补充jvm压缩指针栗子&#xff1a; 对象头包含什么对象怎么定位&#xff1f;**句柄方式和直接引用的优缺点&#xff1a;** 对象怎么分配&#xff1f;为什么hotspot不使用c对象来代…