模板模式

前言:边动手,边动脑,才能进步,只动手不动脑,一塌糊涂
定义

又称模板方法模式,定义一个算法的骨架,并且允许子类为一个或多个步骤提供实现,属于行为性设计模式

用途

用来梳理流程标准化的业务场景

应用场景

一次性实现一个算法不变的部分,并将可变的部分留给子类去实现

Demo1

以员工从一家公司离职到另一家公司面试并上班为例(假定必须先离职才能去面试)

package com.ns.template.demo1;

/**
 * 找工作类(抽象类,部分方法为protected修饰--保证子类可访问,部分方法为final修饰--保证方法不被允许修改)
 */
public abstract class FindWork {

    /**
     * 找工作方法,protected定义保证只有子类才能调用
     */
    protected final void find(){

        //1.先给当前公司提交离职申请
        this.applyLeave();
        //2.审批通过
        this.approveLeave();
        //3.拿到离职证明
        this.getLeaveProve();
        //4.找到下家要面试的公司
        this.findCompany();
        //5.人事面试
        this.personalInterview();
        //6.技术面试
        this.technologyInterview();
        //7.提交各种资料(不一定是必须的)
        //在模板模式中,此类方法被称作钩子方法,用来灵活的干预流程
        if(necessary()){
            submitInformation();
        }
        //8.入职
        this.doWork();
    }

    final void doWork() {
        System.out.println("入职办理完成,开始上班了");
    }

    abstract void submitInformation();

    protected boolean necessary() {
        return false;
    }

    final void technologyInterview() {
        System.out.println("技术面试也通过了,准备办理入职");
    }

    final void personalInterview() {
        System.out.println("物色到一家不错的公司,人事面试通过了");
    }

    final void findCompany() {
        System.out.println("目前成为了无业人员,开始寻找下家公司");
    }

    final void getLeaveProve() {
        System.out.println("员工拿到离职证明");
    }

    final void approveLeave() {
        System.out.println("公司同意该员工离职");
    }

    final void applyLeave(){
        System.out.println("准备申请离职");
    }
}

package com.ns.template.demo1;

/**
 * 普通员工,不需要提交任何入职资料,不需要重写钩子方法
 */
public class GeneralPerson extends FindWork{
    @Override
    void submitInformation() {
    }
}

package com.ns.template.demo1;

/**
 * 特殊员工,需要提交入职部分资料,通过重写钩子方法
 */
public class SpecialPerson extends FindWork{

    private Boolean necessary;

    public SpecialPerson(Boolean necessary){
        this.necessary = necessary;
    }

    @Override
    void submitInformation() {
        System.out.println("提交离职证明");
        System.out.println("提交薪资流水单");
    }

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

package com.ns.template.demo1;

/**
 * 测试类
 */
public class TestTemplate {
    public static void main(String[] args) {
        GeneralPerson generalPerson = new GeneralPerson();
        generalPerson.find();

        SpecialPerson specialPerson = new SpecialPerson(true);
        specialPerson.find();
    }
}

Demo2

以JDBC连接数据库的过程为例

package com.ns.template.demo2;

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;

/**
 * JDBC连接、数据获取、释放类
 */
public abstract class JdbcTemp {
    private DataSource dataSource;

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

    public List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values){
        List<?> result;
        try {
            //1.获取连接,从dataSource中获取
            Connection coon = this.getConnection();
            //2.创建语句集,通过连接对象创建执行语句
            PreparedStatement pstm = this.createStatement(coon,sql);
            //3.执行语句集,设置参数并执行
            ResultSet rs = this.executeSql(pstm,values);
            //4.处理结果集
            result = this.parseResultSet(rs,rowMapper);
            //5.关闭结果集
            this.closeResultSet(rs);
            //6.关闭语句集
            this.closeStatement(pstm);
            //7.关闭连接
            this.closeConnection(coon);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return result;
    }

    private void closeConnection(Connection coon) throws SQLException {
        coon.close();
    }

    private void closeStatement(PreparedStatement pstm) throws SQLException {
        pstm.close();
    }

    private void closeResultSet(ResultSet rs) throws SQLException {
        rs.close();
    }

    private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws SQLException {
        List<Object> result = new ArrayList<>();
        int rowNum = 1;
        while (rs.next()){
            result.add(rowMapper.mapRow(rs,rowNum++));
        }
        return result;
    }

    private ResultSet executeSql(PreparedStatement pstm, Object[] values) throws SQLException {
        if(values != null){
            for(int i=0; i<values.length; i++){
                pstm.setObject(i,values[i]);
            }
        }
        return pstm.executeQuery();
    }

    private PreparedStatement createStatement(Connection coon, String sql) throws SQLException {
        return coon.prepareStatement(sql);
    }

    private Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }
}

package com.ns.template.demo2;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 约束ORM逻辑的接口(实现实体之间映射关系)
 * @param <T>
 */
public interface RowMapper<T> {

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

package com.ns.template.demo2;

/**
 * 人员实体类
 */
public class Person {

    private String userCode;
    private String userName;
    private String password;
    private int age;

    public String getUserCode() {
        return userCode;
    }

    public void setUserCode(String userCode) {
        this.userCode = userCode;
    }

    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "userCode='" + userCode + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.ns.template.demo2;

import javax.sql.DataSource;
import java.util.List;

/**
 * 数据库操作类
 */
public class MemberDao extends JdbcTemp {

    public MemberDao(DataSource dataSource) {
        super(dataSource);
    }

    /**
     * 此处可扩展,如果把查询到的字段与实体字段映射起来,而不是一个个get(小小的思考)
     */
    public List<?> select(){
        String sql = "select * from person";
        return super.executeQuery(sql, (RowMapper<Person>) (rs, rowNum) -> {
            Person person = new Person();
            person.setAge(rs.getInt("age"));
            person.setPassword(rs.getString("password"));
            person.setUserCode(rs.getString("user_code"));
            person.setUserName(rs.getString("user_name"));
            return person;
        },null);
    }
}

package com.ns.template.demo2;

import org.apache.commons.dbcp.BasicDataSource;

/**
 * 将数据源初始化封装成简单的单例模式
 */
public class DataSourceSingleton {

    private static BasicDataSource dataSource;

    private DataSourceSingleton(){}

    static {
        dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/redis?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
    }

    public static BasicDataSource getInstance(){
        return dataSource;
    }
}

package com.ns.template.demo2;

import java.util.List;

/**
 * 测试类
 */
public class TestJdbcTemplate {
    public static void main(String[] args) {
        MemberDao memberDao = new MemberDao(DataSourceSingleton.getInstance());
        List<?> result =  memberDao.select();
        System.out.println(result);
    }
}

建表语句

CREATE TABLE `person` (
  `user_code` varchar(10) DEFAULT NULL COMMENT '用户代码',
  `user_name` varchar(20) DEFAULT NULL COMMENT '用户名称',
  `password` varchar(20) DEFAULT NULL COMMENT '密码',
  `age` int(2) DEFAULT NULL COMMENT '年龄'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人员表';

INSERT INTO `person` VALUES ('1', '测试用户1', '123456', '1000');

总结

优点:
1.将相同处理逻辑放到父类,提高了代码的复用性
2.将不同的代码放到子类中处理,提高了代码的可扩展性
缺点:
1.类数目的增加,每个子类都要去继承父类,导致类文件数量的增多
2.父类如果添加新的抽象方法,子类都要跟着修改

最后,希望大家都能学以致用!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值