zoukankan      html  css  js  c++  java
  • 设计模式之 ==> 模板设计模式

    一、什么是模板方法模式

      定义一个操作中的算法骨架,将一些步骤的具体实现延迟到子类当中去实现。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。

    二、模板方法模式的使用场景

    • 在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来放到一个模板抽象类中。
    • 程序主框架相同,细节不同的情况下,也可以使用模板方法。

    三、模板方法模式的写法举例

      下面我们以一个使用 JDBC 查询 MySQL 数据库的例子来介绍一下模板方法模式,首先我们来看一下最初版的实现:

    public class UserQuary {
    
      private static final String URL = "jdbc:mysql://xxx.xxx.xxx.xxx:3306/jdbc";
      private static final String USER_NAME = "xxxx";
      private static final String PASSWORD = "xxxxxx";
    
      public List<User> quary(String sql, List<Object> params) throws Exception {
    
        // 1.建立连接
        Connection connection = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
    
        // 2.建立Statement,并将数据注入预编译sql当中
        PreparedStatement statement = connection.prepareStatement(sql);
        for (int i = 0; i < params.size(); i++) {
          statement.setObject(i + 1, params.get(i));
        }
    
        // 3.执行sql,获取结果
        ResultSet resultSet = statement.executeQuery();
    
        // 4.处理查询结果,将查询结果转换为对应的User对象
        List<User> users = new ArrayList<>();
        while (resultSet.next()) {
          User user = User.builder()
                  .id(resultSet.getLong("id"))
                  .name(resultSet.getString("account_id"))
                  .age(resultSet.getInt("account_name"))
                  .build();
          users.add(user);
        }
    
        // 5.资源关闭
        resultSet.close();
        statement.close();
        connection.close();
    
        // 返回结果
        return users;
      }
    }
    第一版实现

      从以上代码可以看出,这个方法只能查询 user 表,如果我们需要查询其他的表,需要 copy 很多份,在处理查询结果的时候根据对应的表处理成其对应的实体类对象。我们整段代码发现其中总共五个步骤,其中有四个步骤(1,2,3,5)是固定不变的,只有第 4 步对于查询结果的处理,对于不同的表处理的方式不同,对应的实体类模板也不同,那么这就很符合我们上面对模板方法模式的使用场景,我们在父类中实现 1,2,3,5 这四个步骤,第 4 步交给子类去处理。下面我们来进行设计和实现:

    首先,定义一个接口 DBHandler,描述查询方法:

    public interface DBHandler<T> {
    
      /**
       * 参数说明:
       * @param sql --> "select * from tableName where column1 = ? and column2 = ?"
       * @param params --> ["jack", "male"]
       */
      List<T> quary(String sql, List<Object> params);
    
    }

    由于具体不知道查询什么表,所以返回结果使用一个泛型 T。

    然后再来一个抽象类 AbstractDBHandler,把四个固定的步骤(1,2,3,5)在这个父类中实现,而第 4 步使用一个抽象方法交给子类去实现

    public abstract class AbstractDBHandler<T> implements DBHandler<T> {
    
      protected abstract T getResult(ResultSet resultSet);
    
      @Override
      public List<T> quary(String sql, List<Object> params) {
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
    
        try {
          // 1.建立连接
          connection = getConnection();
          // 2.建立statement,并将数据注入预编译sql当中
          statement = getStatement(connection, sql, params);
          // 3.执行查询,获取结果
          resultSet = statement.executeQuery();
          // 4.处理查询结果,将查询结果转换为对应的实体类对象
          List<T> result = new ArrayList<>();
          while (resultSet.next()) {
            T t = getResult(resultSet);
            result.add(t);
          }
          return result;
        } catch (SQLException e) {
          throw new IllegalStateException(e);
        } finally {
          // 5.关闭资源
          release(resultSet, statement, connection);
        }
      }
      
      private Connection getConnection() {
        try {
          return DriverManager.getConnection(ConnectConsts.URL,ConnectConsts.USERNAME,ConnectConsts.PASSWORD);
        } catch (SQLException e) {
          throw new IllegalStateException(e);
        }
      }
    
      private PreparedStatement getStatement(Connection connection, String sql, List<Object> params) throws SQLException {
        PreparedStatement statement = connection.prepareStatement(sql);
        for (int i = 0; i < params.size(); i++) {
          statement.setObject(i + 1, params.get(i));
        }
        return statement;
      }
    
      private void release(ResultSet resultSet, PreparedStatement statement, Connection connection) {
        try {
          if (null != resultSet) {
            resultSet.close();
          }
          if (null != statement) {
            statement.close();
          }
          if (null != connection) {
            connection.close();
          }
        } catch (SQLException e) {
          throw new IllegalStateException(e);
        }
      }
    }
    AbstractDBHandler

    可以看到:第 4 步中只是调用了一下抽线方法 getResult(),具体的实现交给子类。

    再来看一下两个子类:AccountDBHandler 和 UserDBHandler

    public class AccountDBHandler extends AbstractDBHandler<Account> {
    
      @Override
      protected Account getResult(ResultSet resultSet) {
        try {
          return Account.builder()
                  .id(resultSet.getInt("id"))
                  .accountId(resultSet.getString("account_id"))
                  .accountName(resultSet.getString("account_name"))
                  .build();
        } catch (SQLException e) {
          throw new IllegalStateException(e);
        }
      }
    }
    AccountDBHandler
    public class UserDBHandler extends AbstractDBHandler<User> {
    
      @Override
      protected User getResult(ResultSet resultSet) {
        try {
          return User.builder()
                  .id(resultSet.getLong("id"))
                  .name(resultSet.getString("name"))
                  .age(resultSet.getInt("age"))
                  .build();
        } catch (SQLException e) {
          throw new IllegalStateException(e);
        }
      }
    }
    UserDBHandler

    我们可以很清楚的看到,两个子类都是只实现了 getResult() 这个方法,不同的表获取不同的列,然后封装成不同的模板对象。

    最后来看一下具体的方法调用,分别查询 account 表和 user 表.

    public class App {
    
      @Test
      public void test01(){
        String sql = "select * from account where id > ?";
        ArrayList<Object> params = new ArrayList<>();
        params.add(1);
        DBHandler<Account> accountDbHandler = new AccountDBHandler();
        List<Account> accounts = accountDbHandler.quary(sql, params);
        accounts.forEach(System.out::println);
      }
    
      @Test
      public void test02(){
        String sql = "select * from user where id = ? and name = ?";
        ArrayList<Object> params = new ArrayList<>();
        params.add(1);
        params.add("jack");
        DBHandler<User> userDbHandler = new UserDBHandler();
        List<User> accounts = userDbHandler.quary(sql, params);
        accounts.forEach(System.out::println);
      }
    }

    我们只需要构造不同的 sql 和 params 来查询不同的表,使用表对应的实体类模板来封装查询结果。 

  • 相关阅读:
    李宏毅机器学习课程笔记-13.4模型压缩之架构设计
    李宏毅机器学习课程笔记-13.3模型压缩之参数量化
    李宏毅机器学习课程笔记-13.2模型压缩之知识蒸馏
    斗破苍穹 纳兰嫣然 同人换装
    初音未来 捏脸 虚拟歌姬 人物卡 人物数据
    王者荣耀 艾琳 同人换装
    王者荣耀嫦娥 拒霜思 同人 P图
    linux直接IO代码演示
    qt通过http请求下载文件(支持断点续传)
    Q_DECLARE_FLAGS用法
  • 原文地址:https://www.cnblogs.com/L-Test/p/12990207.html
Copyright © 2011-2022 走看看