文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。
相关文章:
- Command命令设计模式
- Singleton单例设计模式
- Decorator装饰设计模式
- Template模板模式
- Strategy策略设计模式
- Proxy代理设计模式
- Factory工厂类设计模式
- 设计模式的6大基本原则
文章目录:
模板方法模式(Template Method Pattern)是一种行为设计模式,它在一个方法中定义了一个算法的骨架,并允许子类在不改变算法结构的情况下重新定义该算法的某些步骤。这个模式通过模板方法来定义算法的步骤,并且这些步骤可以被具体子类实现或覆盖。
模式结构
-
抽象类(AbstractClass):声明了一个模板方法以及若干个抽象操作。模板方法定义了算法的骨架,通常是一个具体方法,包含了调用若干抽象方法的步骤。子类可以通过实现这些抽象方法来改变算法的部分行为。
-
具体类(ConcreteClass):实现了抽象类中的抽象方法,从而在不改变算法结构的情况下实现了算法中的具体步骤。
定义:一个操作中的算法的骨架,而将一些步骤延迟到子类中;模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。例如计算程序运行时间的类,建立起来基本的骨架,把不变的给子类去实现。
思想:侧重点不是选择,你没得选择,你必须这么做,你 可以不参与某一部分内容的自定义;
1.定义一个计算程序运行时间的基本骨架:
package templatepattern;
/**
* @author zhangyu
**/
public abstract class ComputeRunTime {
public final void getTime(){
long start=System.currentTimeMillis();
runCode();
long end=System.currentTimeMillis();
System.out.println("程序运行时间:"+(end-start));
}
public abstract void runCode();
}
2.程序执行的主题类1:
package templatepattern;
/**
* @author zhangyu
**/
public class RunTime extends ComputeRunTime {
@Override
public void runCode() {
for(int i=0;i<Integer.MAX_VALUE;i++){
}
}
}
3.程序执行的主题类2:
package templatepattern;
/**
* @author zhangyu
**/
public class RunTime2 extends ComputeRunTime {
@Override
public void runCode() {
for (int i = 0; i < Integer.MAX_VALUE / 2; i++) { }
}
}
4.测试模板类:
package templatepattern;
/**
* @author zhangyu
* @date 2018/11/7 11:21
**/
public class ComputeRunTimeTest {
public static void main(String[] args) {
RunTime2 rt2 = new RunTime2();
rt2.getTime();
}
}
这个就是典型的模板类,在spring框架中,这种设计模式,在JdbcTempalte中,体现的淋漓尽致;类似于spring中JdbcTemplate的实现方式:
1.Member.java
public class Member {
private String username;
private String password;
private String nickName;
private int age;
private String addr;
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 getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
2.MemberDao.java
public class MemberDao {
//为什么不继承,主要是为了解耦(降低类与类之间的耦合度)
private JdbcTemplate JdbcTemplate = new JdbcTemplate(null);
public List<?> query(){
String sql = "select * from t_member";
return JdbcTemplate.executeQuery(sql,new RowMapper<Member>(){
@Override
public Member mapRow(ResultSet rs, int rowNum) throws Exception {
Member member = new Member();
member.setUsername(rs.getString("username"));
member.setPassword(rs.getString("password"));
member.setAge(rs.getInt("age"));
member.setAddr(rs.getString("addr"));
return member;
}
},null);
}
}
3.JdbcTemplate.java
public class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
private Connection getConnection() throws Exception {
return this.dataSource.getConnection();
}
private PreparedStatement createPreparedStatement(Connection conn, String sql) throws Exception {
return conn.prepareStatement(sql);
}
private ResultSet executeQuery(PreparedStatement pstmt, Object[] values) throws Exception {
for (int i = 0; i < values.length; i++) {
pstmt.setObject(i, values[i]);
}
return pstmt.executeQuery();
}
private void closeStatement(Statement stmt) throws Exception {
stmt.close();
}
private void closeResultSet(ResultSet rs) throws Exception {
rs.close();
}
private void closeConnection(Connection conn) throws Exception {
//通常把它放到连接池回收
}
private List<?> parseResultSet(ResultSet rs, RowMapper rowMapper) throws Exception {
List<Object> result = new ArrayList<Object>();
int rowNum = 1;
while (rs.next()) {
result.add(rowMapper.mapRow(rs, rowNum++));
}
return result;
}
public List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values) {
try {
//1、获取连接
Connection conn = this.getConnection();
//2、创建语句集
PreparedStatement pstmt = this.createPreparedStatement(conn, sql);
//3、执行语句集,并且获得结果集
ResultSet rs = this.executeQuery(pstmt, values);
//4、解析语句集
List<?> result = this.parseResultSet(rs, rowMapper);
//5、关闭结果集
this.closeResultSet(rs);
//6、关闭语句集
this.closeStatement(pstmt);
//7、关闭连接
this.closeConnection(conn);
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
4.RowMapper.java
public interface RowMapper<T> {
public T mapRow(ResultSet rs, int rowNum) throws Exception;
}
5.MemberDaoTest.java
public class MemberDaoTest {
public static void main(String[] args) {
MemberDao memberDao = new MemberDao(null);
memberDao.query();
}
}
这就是模拟了Jdbctemplate对连接数据库进行封装,我们只需要写要查询的sql就好了,然后去读取里面的数据就行。至于模板里面是什么东西,那就不是我们考虑的问题。
模式优点
-
代码复用:算法的骨架由父类定义,具体的实现由子类完成,避免了重复代码。
-
灵活性:子类可以重写算法的某些部分,而不需要修改算法的整体结构。
-
易于扩展:新的子类可以在不修改现有代码的情况下添加新的算法步骤,实现开放/封闭原则。
模式缺点
-
增加复杂度:引入抽象类和子类可能增加系统的复杂性,特别是在简单的算法场景中。
-
设计上的限制:子类只能重写父类提供的算法步骤,无法改变算法的整体框架。
适用场景
- 当你要在多个子类中共享相同的方法、行为时,适合使用模板方法模式。
- 当需要将某个算法的一些步骤延迟到子类中实现时,可以使用该模式。
- 当多个类具有相同的行为,但在某些步骤的实现上有所不同。
模板方法模式在框架开发中非常常见,通过定义一个稳定的算法骨架,允许开发者通过扩展具体的步骤来自定义行为。