设计模式(四)之模板模式(Template Method Pattern)深入浅出

学习目标:

  • 学会用模板模式梳理使用工作中流程标准化的业务场景。
  • 了解JDK源码和Spring源码中对模板模式的运用。

 内容定位:高级知识点,不太适合接触业务场景比较单一的开发者

模板模式的定义:

  • 通常又叫模板方法模式(Template Method Pattern)是指定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现。
  • 模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
  • 属于行为型设计模式

模板模式的适用场景:

  1. 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  2. 各子类中公共的行为被提取出来并集中收集到一个公共的父类中,从而避免代码重复。

模式对比:

抽象工厂模式是用接口实现的,当然也可以用抽象类,重点是归纳和总结对象的创建过程;

模板模式使用的是抽象类,在不改变流程的情况下,定制一些个性化的东西,达到出现不同结果的目的。

策略模式是只提供选择权,内部已经定义好所有的流程,没有干预逻辑的权利,关心的是结果;

模板模式关心整个流程实现的过程,可以微调流程和干预逻辑。

模板模式应用场景案例:

  1. AbstractList的get方法是抽象方法,通过子类实现的,比如ArrayList、LinkedList、ArrayQueue都有各自的get方法实现
  2. GenericServlet的service方法是抽象方法,被HttpServlet实现,划分请求种类的区分
  3. Mybatis源码中的BaseExecutor的doUpdate()、doFlushStatements()、doQuery()、doQueryCursor()方法,不同实现类BatchExecutor、SimpleExecutor、ReuseExecutor、ClosedExecutor。

生活场景案例

案例:网课老师备课需要固定的流程,但是不同的网课课后要求不一样,作业也不一样

网课抽象类

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 15:23
 * @description: 网课抽象类  模板会有一个或者多个未实现的方法,而且这几个未实现方法有着固定的执行顺序
 */
public abstract class NetworkCourse {

    protected final void createCourse(){
//        1、发布预习资料
        this.postPreResource();
//        2、制作PPT课件
        this.createPPT();
//        3、在线直播
        this.liveVideo();
//        4、提交课件、课堂笔记
        this.postNode();
//        5、提交源码
        this.postSource();
//        6、布置作业,有些课有作业有些课没有作业
//        如果有作业的话,检查作业,没有作业,完成了
        if (needHomework()){
            checkHomework();
        }
    }

    abstract void checkHomework();

    /**
     * 钩子方法: 作用实现流程微调
     */
    protected boolean needHomework(){
        return false;
    };

    final void postSource(){
        System.out.println("提交源代码");
    };

    final void postNode(){
        System.out.println("提交课件和笔记");
    };

    final void liveVideo(){
        System.out.println("直播授课");
    };

    final void createPPT(){
        System.out.println("创建备课PPT");
    };

    final void postPreResource(){
         System.out.println("分发预习资料");
     };
}

Java课

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 15:34
 * @description:
 */
public class JavaCourse extends NetworkCourse {
    @Override
    void checkHomework() {
        System.out.println("检查Java架构的作业");
    }
}

大数据课

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 15:35
 * @description:
 */
public class BigDataCourse extends NetworkCourse {

    /**
     * 是否有作业
     */
    private boolean needHomeworkFlag = false;

    public BigDataCourse(boolean needHomeworkFlag) {
        this.needHomeworkFlag = needHomeworkFlag;
    }

    @Override
    void checkHomework() {
        System.out.println("检查大数据的课后作业");
    }

    @Override
    protected boolean needHomework() {
        return this.needHomeworkFlag;
    }
}

测试

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 15:40
 * @description:
 */
public class NetworkCourseTest {
    public static void main(String[] args) {
        System.out.println("-------Java架构师课程-------");
        NetworkCourse javaCourse = new JavaCourse();
        javaCourse.createCourse();

        System.out.println("-----大数据课程-----");
        NetworkCourse bigDataCourse = new BigDataCourse(true);
        bigDataCourse.createCourse();
    }
}

运行结果

 附上类结构图

业务场景案例


案例:简单实现spring的jdbcTemplate

RowMapper接口:结果集映射

/**
 * 功能描述:  ORM映射定制化的接口
 *
 * @Param:
 * @Return:
 * @Author: ZhouCong
 * @Date: 2021/1/11 15:55
 */
public interface RowMapper<T> {

    T mapRow(ResultSet rs, int rowNum) throws Exception;
}

JdbcTemplate

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 15:55
 * @description:
 */
public abstract class JdbcTemplate {
    private DataSource dataSource;

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

    public List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values) {
        try {
//            1、获取链接
            Connection connection = this.getConnection();
//            2、创建语句集
            PreparedStatement prepareStatement = this.createPrepareStatement(connection, sql);
//            3、执行语句集
            ResultSet rs = this.executeQuery(prepareStatement,values);
//            4、处理结果集
            List<?> result = this.paresResultSet(rs, rowMapper);
//            5、关闭结果集
            this.closeResultSet(rs);
//            6、关闭语句集
            this.closePreperStatement(prepareStatement);
//            7、关闭连接
            this.closeConnection(connection);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    protected void closeConnection(Connection connection) throws Exception {
//        数据库连接池可以不关闭
        connection.close();
    }

    final void closePreperStatement(PreparedStatement prepareStatement) throws Exception {
        prepareStatement.close();
    }

    final void closeResultSet(ResultSet rs) throws Exception {
        rs.close();
    }

    protected List<?> paresResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception {
        List<Object> result = new ArrayList<>();
        int rowNum = 0;
        while (rs.next()){
            result.add(rowMapper.mapRow(rs,++rowNum));
        }
        return result;
    }

    protected ResultSet executeQuery(PreparedStatement prepareStatement, Object[] values) throws Exception {
        for (int i = 0; i < values.length; i++) {
            prepareStatement.setObject(i+1,values[i]);
        }
        return prepareStatement.executeQuery();
    }

    protected PreparedStatement createPrepareStatement(Connection connection, String sql) throws Exception {
        return connection.prepareStatement(sql);
    }

    public Connection getConnection() throws Exception {
        return this.dataSource.getConnection();
    }
}

Member实体类

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 16:27
 * @description:
 */
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;
    }
}

MemberDao

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 16:30
 * @description:
 */
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>() {

            @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.setNickname(rs.getString("nickname"));
                member.setAge(rs.getInt("age"));
                member.setAddress(rs.getString("address"));
                return member;
            }
        },null);
    }
}

测试

/**
 * @author: ZhouCong
 * @date: Create in 2021/1/11 16:48
 * @description:
 */
public class MemberDaoTest {

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

}

附上类结构图

总结 

模板模式的优点:

  1. 提高代码的复用性:将相同的逻辑提取到父类中,将不同的代码逻辑让子类实现
  2. 提高代码的扩展性:提供代码逻辑流程的微调
  3. 符合开闭原则

模板模式的缺点:

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

以上对模板模式的介绍到此结束,欢迎批评指正。 附:源码地址

原文地址:https://www.cnblogs.com/itzhoucong/p/14262174.html