java设计模式--模板模式

java

目录

  • 模板模式
  • 适用场景
  • 模仿JdbcTemplate的模板模式
  • 优点
  • 缺点
  • 框架中常见的模板方法

模板模式

通常又叫模板方法模式,定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现.

​ 模板方法使得子类可以再不改变算法结构的情况下,重新定义算法的某些步骤. 是行为型设计模式.

适用场景

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

各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复;

常见的应用:AbstractListHttpServletservice方法、Spring的 JdbcTemplateTomcat的架构中.

模仿JdbcTemplate的模板模式

​ 简单模仿 SpringJdbcTemplateJDBC操作可以理解为有流程的,可以复制的.最开始学习JDBC操作时:打开连接 → 获取语句集 → 设置参数、执行语句集 → 处理结果集 → 关闭连接 .

JdbcTemplate代码

package com.template;

import javax.sql.DataSource;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;

public class JdbcTemplate {

private DataSource dataSource;

public JdbcTemplate(DataSource dataSource){this.dataSource=dataSource;}

public <T> List<T> executeQuery(String sql,Object[] args,RowMapper<T> rowMapper){

PreparedStatement ps=null;

Connection connection=null;

try {

//1.获取连接

connection =this.getConnection(dataSource);

//2.获得语句集

ps = createPreparedStatement(connection, sql);

//3.执行语句集得到ResultSet

ResultSet rs=doExecuteQuery(ps,args);

//4.处理结果集

List<T> result = parseResultSet(rs,rowMapper);

return result;

}catch (Exception e){

e.printStackTrace();

}finally {

//5.释放资源.

closePreparedStatement(ps);

closeConnection(connection);

}

return null;

}

private void closeConnection(final Connection connection) {

try {

connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

private void closePreparedStatement(final PreparedStatement ps) {

try {

ps.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

private <T> List<T> parseResultSet(final ResultSet rs, final RowMapper<T> rowMapper) throws Exception {

List<T> result=new ArrayList<>();

int rowNum=1;

while(rs.next()){

result.add(rowMapper.mapperRow(rs,rowNum++));

}

return result;

}

private ResultSet doExecuteQuery(final PreparedStatement ps, final Object[] args) throws SQLException {

for (int i=0;i<args.length;i++){

ps.setObject( i+1,args[i]);

}

return ps.executeQuery();

}

private PreparedStatement createPreparedStatement(Connection connection,String sql) throws SQLException {

return connection.prepareStatement(sql);

}

protected Connection getConnection(final DataSource dataSource) throws SQLException {

return dataSource.getConnection();

}

}

RowMapper接口

RowMapper接口可以理解为是 钩子,用来在JdbcTemplate模板方法处理结果集时使用.

package com.template;

import java.sql.ResultSet;

public interface RowMapper<T> {

T mapperRow(ResultSet rs,int rowNum) throws Exception;

}

UserDao测试效果

package com.template;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;

import java.sql.ResultSet;

import java.util.List;

public class UserDao extends JdbcTemplate {

private static final Object[] EMPTY_ARGS=new Object[0];

public UserDao(final DataSource dataSource) {

super(dataSource);

}

public List<User> selectAll(){

String sql="select * from user";

return super.executeQuery(sql, EMPTY_ARGS, new RowMapper<User>() {

@Override

public User mapperRow(final ResultSet rs, final int rowNum) throws Exception {

User user = new User();

user.setId(rs.getInt("id"));

user.setName(rs.getString("name"));

user.setAge(rs.getInt("age"));

user.setSex(rs.getString("sex"));

return user;

}

});

}

public static void main(String[] args) throws Exception {

Class.forName("com.mysql.jdbc.Driver");

ComboPooledDataSource dataSource = new ComboPooledDataSource();

dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");

dataSource.setDriverClass("com.mysql.jdbc.Driver");

dataSource.setUser("root");

dataSource.setPassword("yourPassword");

UserDao dao = new UserDao(dataSource);

List<User> users = dao.selectAll();

for(User user:users){

System.out.println(user);

}

}

}

代码测试效果

优点

提高代码复用、扩展性,符合开闭原则

缺点

增加系统复杂度 ;父类添加抽象方法,所有子类都需要重写抽象方法;

框架中常见的模板方法

1.JDK中 AbstractList.get

常见的ArrayListVector就是AbstractList的实现,ArrayList返回数组中的index下标的元素.

  1. Servlet-api

service方法继续调用service(HttpServletRequest,HttpServletResponse)方法,进一步根据请求方法来决定调用doGetdoPost等,我们以前开发时候写Servlet,有时候重写doGetdoPost方法来.

​ 上面的例子,你可能觉得模板方法只是实现抽象方法,但是在Tomcat中模板方法的使用可以说是非常精妙了.

  1. Tomcat

Tomcat几大组件 Server、Service、Engine、Host、Context、Connector都继承了LifecycleBase抽象类.

LifecycleBase的init、start、stop、destroy都采用了模板方法,其中以init方法为例分析:

public final synchronized void init() throws LifecycleException {

if (!state.equals(LifecycleState.NEW)) {

//组件初始化前判断状态是否是新生NEW的

invalidTransition(Lifecycle.BEFORE_INIT_EVENT);

}

try {

//设置组件状态进入 `开始初始化之前`

setStateInternal(LifecycleState.INITIALIZING, null, false);

//不同组件采用不同实现,来完成组件的初始化

initInternal();

//组件状态设置为 初始化结束

setStateInternal(LifecycleState.INITIALIZED, null, false);

} catch (Throwable t) {

ExceptionUtils.handleThrowable(t);

setStateInternal(LifecycleState.FAILED, null, false);

throw new LifecycleException(

sm.getString("lifecycleBase.initFail",toString()), t);

}

}

//不同组件的初始化具体逻辑需要重写

protected abstract void initInternal() throws LifecycleException;

所以,Tomcat每个组件一般都会重写 initInternal、startInternal等模板方法,代码看起来完全不冗余,也符合开闭利于扩展新的组件.

以上是 java设计模式--模板模式 的全部内容, 来源链接: utcz.com/z/391364.html

回到顶部