zoukankan      html  css  js  c++  java
  • 一天一个设计模式——模板方法(Template Method)模式

    一、模式说明

      现实世界中的模板是用于将事物的结构规律予以固定化、标准化的成果,它体现了结构形式的标准化。例如镂空文字印刷的模板,通过某个模板印刷出来的文字字体大小都是一模一样,但是具体使用什么材质的颜料,什么颜色的颜料来印刷文字,取决于具体实际业务场景的需要。由此可见,模板制定了某些固定的条条框框,以及事物的处理标准流程,但是并没有说明如何去做,具体如何做,取决于使用模板的人。

      在程序设计领域,模板是具有一系列抽象方法的接口类,单看接口类,我们只能知道这个模板有哪些抽象方法以及这些方法的调用顺序,但最终这些方法具体做什么操作,仅从模板类无法得知。继承模板的不同的子类,对这些抽象方法可以有不同的实现,当父类的模板方法被调用时,程序就可以有不同的行为实现。

      像这样,在父类中定义处理流程的框架,在子类中实现具体处理的模式,称为模板方法模式。

      在通常的面向对象程序设计中,我们习惯于站在子类的角度思考问题:例如子类继承了父类的哪些方法和属性,子类如何扩展父类实现新的功能,子类如何覆盖父类的方法来改变程序的行为。现在换一种角度,站在父类的角度思考子类:期待子类需要实现的抽象方法,要求子类必须实现的抽象方法。这也是Java面向对象程序设计中抽象类设计的特点:抽象类并不说明具体要执行的操作,但是抽象类可以提前决定继承它的子类中的方法名(抽象类中的方法名),并定义这些方法的处理流程,这种在抽象阶段决定处理流程非常重要:

    • 使处理逻辑通用化,父类模板方法中已经写好了每个方法调用的时机,并处理这些方法的结果,实现业务算法,因此子类无需重复编写如何调用这些方法的算法。
    • 在子类中实现父类的抽象方法时,需要充分理解这些抽象方法的调用时机,从而实现子类与父类之间的协作。
    • 父类与子类的一致性,根据里氏替换原则(LSP),可以使用父类的变量保存子类的实例,且无论变量保存的是哪个子类实例,调用父类的模板方法,程序都可以正常工作。

      举个具体的例子,在程序中访问数据库,无论是什么数据库(mysql、oracle、h2),要操作它们都要做一些特定步骤的操作:

    • 1. 建立数据库连接
    • 2. 创建Connection连接
    • 3. 创建statement或者preparedStateement
    • 4. 执行sql,返回ResultSet
    • 5. 关闭resultSet
    • 5.关闭statement
    • 6.关闭Connection

      Spring针对不同的平台,提供了几种不同的模板:

    • 直接使用JDBC:提供了JdbcTemplate
    • 使用ORM框架:HibernateTemplate和JpaTemplate

    二、模板方法(Template Method)模式类图

    三、模板方法(Template Method)模式中的角色

    • AbstractClass抽象类:负责实现模板方法,并声明要用到的抽象方法。
    • ConcreteClass具体类:负责实现AbstractClass抽象类中的抽象方法,这些方法会被AbstactClass抽象类中的模板方法调用。

    四、代码示例

    这里使用Spring的JDBCTemplate来演示模板方法模式:

    1:创建java控制台应用程序,并添加spring相关依赖(或者使用maven创建java项目),项目目录结构如下:

    注:adapterpattern包和iteratorpattern包是之前设计模式的代码示例包,无需理会(也可以查看我之前的博客,里面有说明这些代码是如何创建的)。

    2:创建数据源的Bean,即上图中的ContextBeans类:

    package com.designpattern.cn.templatemethodpattern;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;
    import org.springframework.stereotype.Component;
    
    import javax.sql.DataSource;
    
    @Component
    public class ContextBeans {
        @Bean
        public DataSource dataSource(){
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://10.211.55.100:3306/fruit_sale_system");
            dataSource.setUsername("root");
            dataSource.setPassword("123456");
            return dataSource;
        }
    }
    View Code

    3:启用Spring容器的自动扫描配置类SpringConfig:

    package com.designpattern.cn.templatemethodpattern;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan
    public class SpringConfig {
    }
    View Code

    4:测试使用模板方法操作数据库执行结果:

    可以看到上述代码中,我只进行了Spring的基本配置,并为项目设置了一个mysql数据源,通过创建模板的实例JdbcTemplate,就可以直接调用queryForObject模板方法,实现业务查询。

    五、相关的模式

    • 工厂方法(FactoryMethod)模式:工厂方法模式是将模板方法用于生成实例的的典型例子。
    • 策略(Strategy)模式:模板方法模式中,使用继承来改变程序的行为,而在策略模式中,使用委托改变程序的行为,并替换整个算法。
  • 相关阅读:
    03点云文件常用格式转换(pcd,txt,ply,obj,stl)
    04点云数据结构格式
    vs2015 +ZXing/Zbar的环境配置
    01PCL 点云+vs2015在win10下的环境配置
    07点云的滤波与分割
    gitlabCI/CD部署一个java项目
    k8s 为什么需要数据卷
    gitlab Runner 安装与部署
    gitlab ci/cd介绍
    k8s emptyDir临时数据卷
  • 原文地址:https://www.cnblogs.com/zheng-hong-bo/p/11072945.html
Copyright © 2011-2022 走看看