• 设计模式(四)之模板模式(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. 继承关系自身的缺点:如果父类添加了新的抽象方法,所有的子类都要改一遍

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

  • 相关阅读:
    打造jQuery的高性能TreeView
    结构化日志类库 ---- Serilog库
    项目管理上的失误和应对措施
    Android分类导航
    Android破解
    Android开发入门
    安装 Android Studio 2.3 详细过程及错误解决
    Python学习思维导图
    设计模式的六大原则 ---- 理论知识
    日志的艺术(The art of logging)
  • 原文地址:https://www.cnblogs.com/itzhoucong/p/14262174.html
Copyright © 2020-2023  润新知