模版方法模式解密:编写可复用、可维护的代码新境界!

文章目录

  • 一、概念
  • 二、生活中应用场景
  • 三、角色
  • 四、代码实现
  • 五、模版方法模式实现JDBC的操作
    • 1. 创建约束ORM逻辑的接口RowMapper
    • 2.创建封装了所有处理流程的抽象类JdbcTemplate
    • 3.创建实体对象Member类
    • 4.创建数据库操作类MemberDao
    • 5. 客户端测试代码
  • 总结
    • 优点
    • 缺点


一、概念

  1. 属于行为型设计模式
  2. 本质抽象封装流程,具体实现。也就是用抽象类将一个固定流程封装起来,具体步骤由不同的子类实现。
  3. 实现是通过类的继承。

二、生活中应用场景

炒菜:洗锅——>点火——>热锅——>上油——>下原料——>翻炒——>放调料——>出锅

三、角色

抽象模板(AbstractClass):抽象模板列,定义了一套算法框架/流程;
具体实现(ConcreteClass):具体实现类,对算法框架/流程的某些步骤进行了实现。

四、代码实现

以在线课程为例

抽象模板AbstractCourse

public abstract class AbstractCourse {public final void createCourse(){//1. 发布预习资料postPreResource();//2. 制作课件createPPT();//3. 直播授课liveVideo();//4. 上传课后资料postResource();//5. 布置作业postHomework();if(needCheckHomework()){checkHomework();}}/*** 检查作业*/protected abstract void checkHomework();//钩子方法/***  判断是否需要检查作业*/protected boolean needCheckHomework(){return true;}protected void postHomework(){System.out.println("布置作业");}protected void postResource(){System.out.println("上传课后资料");}protected void liveVideo(){System.out.println("直播授课");}protected void createPPT(){System.out.println("制作课件");}protected void postPreResource(){System.out.println("发布预习资料");}
}

具体实现:
Java课程实现类

public class JavaCourse extends AbstractCourse{private boolean needHomework=false;public void setNeedHomework(boolean needHomework) {this.needHomework = needHomework;}@Overrideprotected void checkHomework() {System.out.println("检查Java作业");}@Overrideprotected boolean needCheckHomework() {return super.needCheckHomework();}
}

Python课程实现类:

public class PythonCourse  extends AbstractCourse{@Overrideprotected void checkHomework() {System.out.println("检查Python作业");}
}

客户端测试代码

public class Test {public static void main(String[] args) {System.out.println("======架构师课程======");JavaCourse javaCourse = new JavaCourse();javaCourse.setNeedHomework(false);javaCourse.createCourse();System.out.println("======Python课程======");PythonCourse pythonCourse = new PythonCourse();pythonCourse.createCourse();}
}

五、模版方法模式实现JDBC的操作

1. 创建约束ORM逻辑的接口RowMapper

public interface RowMapper<T> {/*** 将 ResultSet 中的行映射为一个对象 T* @param rs ResultSet 对象* @param rowNum 行数* @return 映射后的对象 T* @throws Exception 抛出异常*/T mapRow(ResultSet rs, int rowNum) throws Exception;
}

2.创建封装了所有处理流程的抽象类JdbcTemplate

public class JdbcTemplate {@SuppressWarnings("all")private DataSource dataSource;public JdbcTemplate(DataSource dataSource) {this.dataSource = dataSource;}public final List<?> executeQuery(String sql, RowMapper rowMapper, Object... values) {try {//1.获取连接Connection conn=this.getConnection();//2.创建语句集PreparedStatement pstm= this.createStatement(conn, sql);//3.执行语句集ResultSet rs = this.executeQuery(pstm,values);//4.处理结果集List<?> result=this.parseResultSet(rs,rowMapper);//5.关闭结果集rs.close();//6.关闭语句集pstm.close();//7.关闭连接conn.close();return result;} catch (Exception e) {e.printStackTrace();}return null;}private List<?> parseResultSet(ResultSet rs, RowMapper rowMapper) throws Exception {List<Object> result=new ArrayList<>();int rowNum=0;while (rs.next()) {Object obj=rowMapper.mapRow(rs, rowNum++);result.add(obj);}return result;}private ResultSet executeQuery(PreparedStatement pstm, Object[] values) throws SQLException {for (int i = 0; i < values.length; i++) {pstm.setObject(i , values[i]);}return pstm.executeQuery();}private PreparedStatement createStatement(Connection conn, String sql) throws SQLException {return conn.prepareStatement(sql);}private Connection getConnection() throws SQLException {return this.dataSource.getConnection();}
}

3.创建实体对象Member类

public class Member {private String username;private String password;private String nickname;private int age;private String address;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
}

4.创建数据库操作类MemberDao

public class MemberDao extends JdbcTemplate {public MemberDao(DataSource dataSource) {super(dataSource);}public List<?> selectAll() {String sql = "select * from t_member";return super.executeQuery(sql, new RowMapper<Member>() {@Overridepublic Member mapRow(ResultSet rs, int rowNum) throws Exception {Member member = new Member();member.setUsername("username");member.setPassword("password");member.setAge(rs.getInt("age"));member.setAddress(rs.getString("address"));return member;}},null);}
}

5. 客户端测试代码

public class Test {public static void main(String[] args) {MemberDao memberDao = new MemberDao(null);List<?> result=memberDao.selectAll();System.out.println(result);}
}

总结

优点

  1. 将相同处理逻辑封装到抽象父类中,提高代码的复用性
  2. 不同的代码放到子类中,通过子类扩展增加新的行为,提高代码的扩展性。

缺点

  1. 类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加,增加了系统实现的复杂度
  2. 继承关系的自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍。

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

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

相关文章

C#检查服务状态,以及进行服务启停

1. linux环境 linux环境通过执行bash命令直接执行&#xff1a; public string RunCmdLinux(string cmd){var proc new Process();System.Console.Write($"Run Linux cmd > [{cmd}] START!");proc.StartInfo.CreateNoWindow true;proc.StartInfo.FileName &…

git clone:SSL: no alternative certificate subject name matches target host name

git clone 时的常见错误&#xff1a; fatal: unable to access ‘https://ip_or_domain/xx/xx.git/’: SSL: no alternative certificate subject name matches target host name ‘ip_or_domain’ 解决办法&#xff1a; disable ssl verify git config --global http.sslVe…

Redis分布式锁(中)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 我们在不久前介绍了Spr…

JavaEE初阶(18)(JVM简介:发展史,运行流程、类加载:类加载的基本流程,双亲委派模型、垃圾回收相关:死亡对象的判断算法,垃圾回收算法,垃圾收集器)

接上次博客&#xff1a;初阶JavaEE&#xff08;17&#xff09;Linux 基本使用和 web 程序部署-CSDN博客 目录 JVM 简介 JVM 发展史 JVM 运行流程 JVM的内存区域划分 JVM 执行流程 堆 堆的作用 JVM参数设置 堆的组成 垃圾回收 堆内存管理 类加载 类加载的基本流…

Flink(五)【DataStream 转换算子(上)】

前言 这节注定是一个大的章节&#xff0c;我预估一下得两三天&#xff0c;涉及到的一些东西不懂就重新学&#xff0c;比如 Lambda 表达式&#xff0c;我只知道 Scala 中很方便&#xff0c;但在 Java 中有点发怵了&#xff1b;一个接口能不能 new 来构造对象? 答案是可以的&…

Vue模板语法

模板语法有两大类&#xff1a; 1.插值语法 2.指令语法 让我为大家介绍一下吧&#xff01; 一、插值语法 功能:用于解析标签体内容。 写法: {{xxx}}&#xff0c;xxx是js表达式&#xff0c;且可以直接读取到data中的所有属性。 举个例子&#xff1a; <!DOCTYPE html> &l…

idea maven 构建本地jar包及pom文件

1、设置模块build 本地输出路径 <build><defaultGoal>compile</defaultGoal><resources><resource><directory>${basedir}/src/main/resources</directory><includes><include>**/**</include></includes>…

腾讯云服务器可用区是什么意思?

腾讯云服务器可用区是什么意思&#xff1f;云服务器可用区如何选择&#xff1f;可用区是指在同一个地域内电力和网络相互独立的区域&#xff0c;可用区可以做到故障隔离&#xff0c;所以可用区存在的意义在于构建高可用、高容灾应用&#xff0c;将应用部署在不同可用区内&#…

Linux 下安装 Maven 3.8.8【详细步骤】

前提条件:安装 jdk,详见 安装jdk1.8 # 下载(地址可能会因为版本更新无效,到时候直接去官网找下载地址) wget https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz# 解压 tar -zxvf apache-maven-3.8.8-bin.tar.gz# 修改环境变量 vi /e…

ChatkBQA:一个基于大语言模型的知识库问题生成-检索框架11.13

ChatkBQA&#xff1a;一个基于大语言模型的知识库问题生成-检索框架 摘要1 引言3 准备工作4 方法4.1 ChatKBQA概述4.2 在LLMS上进行高效微调4.3 用微调LLMS生成逻辑形式4.4 实体和关系的非监督检索4.5 可解释查询执行 摘要 基于知识的问答&#xff08;KBQA&#xff09;旨在从大…

Windows Server 2012 R2系统服务器远程桌面服务多用户登录配置分享

Windows Server 2012系统在没有安装远程多界面的情况下&#xff0c;最多只能同时运行2个远程桌面&#xff0c;如果是有多个技术员、合伙人同时操作或是像游戏开发需要用到多界面&#xff0c;但是没有安装就很不方便&#xff0c;今天飞飞来和你们分享Windows server 2012R2系统远…

C++ opencv基本用法【学习笔记(九)】

这篇博客为修改过后的转载&#xff0c;因为没有转载链接&#xff0c;所以选了原创 文章目录 一、vs code 结合Cmake debug1.1 配置tasks.json1.2 配置launch.json 二、图片、视频、摄像头读取显示2.1 读取图片并显示2.2 读取视频文件并显示2.3 读取摄像头并写入文件 三、图片基…

通过注释来埋点

目录 开始 插件编写 功能一 功能二 功能三 合并功能 运行代码 总结 这篇文章主要讲如何根据注释&#xff0c;通过babel插件自动地&#xff0c;给相应函数插入埋点代码&#xff0c;在实现埋点逻辑和业务逻辑分离的基础上&#xff0c;配置更加灵活 这篇文章想要达到的效…

非原始值的响应式方案

实际上&#xff0c;实现响应式数据要比想象中难很多&#xff0c;并不是单纯地拦截get/set 操作即可。举例来说&#xff0c;如何拦截 for…in 循环&#xff1f;track 函数如何追踪拦截到的 for…in 循环&#xff1f;类似的问题还有很多。除此之外&#xff0c;我们还应该考虑如何…

Stm32_标准库_18_串口蓝牙模块_手机与蓝牙模块通信_控制LED灯亮灭

通过输入LED_ON和LED_OFF分别控制LED灯的亮与灭 接线&#xff1a; LED的正极接正电&#xff0c;负极接GPIOA_Pin1 蓝牙模块TXD接GPIOA_Pin3,VCC接正电&#xff0c;GND接负电 注意&#xff1a;USART2是APB1外设&#xff0c;汉字占用字节数是字符的两倍 使用&#xff1a; 手…

2023最受推荐的五款项目管理工具

1、进度猫 进度猫是国内一款轻量级项目管理工具&#xff0c;适用于实时协作的团队。 以甘特图为向导&#xff0c;基于任务清单todolist&#xff0c;支持多用户协作&#xff1b; 甘特图显示具体任务清单、时间和任务的进度&#xff1b; 对未完成任务、已完成任务进行分类管…

WPF中的虚拟化是什么

WPF&#xff08;Windows Presentation Foundation&#xff09;中的虚拟化是一种性能优化技术&#xff0c;它主要用于提高大量数据展示的效率。在WPF中&#xff0c;如果你有一个包含大量项的ItemsControl&#xff08;例如ListBox、ListView或DataGrid等&#xff09;&#xff0c;…

Vue3源码reactive和readonly对象嵌套转换,及实现shallowReadonly

前言 官方文档中对reactive的描述&#xff1a; 响应式转换是“深层”的&#xff1a;它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性&#xff0c;同时保持响应性。 官方文档中对readonly的描述: 只读代理是深层的&#xff1a;对任何嵌套属性的访问都将是…

[vim]Python编写插件学习笔记2 - 分离

0 环境 Windows 11 22H2gVim82 (D:/ProgramFiles/Vim)Python311 (D:/ProgramFiles/Python311)Vundle v0.10.2 阅读本文前&#xff0c;需要先了解前文: 《[vim]Python 编写插件学习笔记1 - 开始》 1 Python 与 vimscript 分离 前文编写 vim 插件的方式&#xff0c;是将 Pyt…