最近在做批量合同生成业务,合同之间不同 ,每个合同均有一个模板。业务大致是数据准备(一致)、生成合同号(规则不同)、生成合同(模板不同)、上传合同(一致)。那么我们可以就根据这个业务来梳理一下模板模式。
模板模式实现示例
模板(方法)模式属于行为型模式,它定义一个操作中的算法的骨架,而将一些步骤推迟到子类当中实现。父类抽取并实现的是公共方法,对于可变方法,父类做的只是定义了可变行为的接口,具体实现留给子类去完成,实现对代码的重复利用。
- 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架
- 具体类(ConcreteClass):实现抽象类中的抽象方法,用于完成完整的算法
public abstract class AbstractTemplate { private String params; public AbstractTemplate(String params){ this.params= params; } public void question(){ System.out.println("第一步,准备数据"); System.out.println("第二步,生成合同编码号"); generContractNo(); System.out.println("第三步,获取合同模板并批量生成合同"); //将params替换模板内参数,生成合同 getContractTemplate(params); System.out.println("第四步,上传合同"); } public abstract int generContractNo(); public abstract int getContractTemplate();}//合同A模板public class ContractATemplate extends AbstractTemplate{ @Override public int generContractNo() { return 111; } @Override public int getContractTemplate(){ return 123; } public ContractATemplate(String params) { super(params); }}//合同B模板public class ContractBTemplate extends AbstractTemplate{ @Override public int generContractNo() { return 222; } @Override public int getContractTemplate(){ return 456; } public ContractBTemplate(String params) { super(params); }}
@Testpublic void templatePatternTest(){ String params = "{id:'0001',name:'0001'}"; AbstractTemplate aTempate = new ContractATemplate(params); AbstractTemplate bTempate = new ContractBTemplate(params); aTempate.question(); bTempate.question();}
模板模式在spring中的运用
spring中的JdbcTemplate类就运用了模板方法,Java在执行数据库操作时的步骤无非如下几步:
1. 加载驱动 2. 建立连接 3. 获取Statement 4. 拼接参数(针对PreparedStatement) 5. 执行 6. 返回结果 7. 销毁连接在这里只是简单,介绍一下,因此针对PreparedStatement,最大的可变之处就是5,6这个部分,因此JdbcTemplate将 1,2,3,4,7制作成模板(主要在execute*方法中),而对于5,6它通过匿名内部类的形式来实现(也就是说对于update、query等等 操作,都对5,6通过匿名内部类有不同的实现,匿名内部类实现的都是*callback接口,*callback都是额外定义的接口)
@OverridepublicT query(final String sql, final ResultSetExtractor rse) throws DataAccessException { Assert.notNull(sql, "SQL must not be null"); Assert.notNull(rse, "ResultSetExtractor must not be null"); if (logger.isDebugEnabled()) { logger.debug("Executing SQL query [" + sql + "]"); } //匿名内部类 class QueryStatementCallback implements StatementCallback , SqlProvider { @Override public T doInStatement(Statement stmt) throws SQLException { ResultSet rs = null; try { rs = stmt.executeQuery(sql); ResultSet rsToUse = rs; if (nativeJdbcExtractor != null) { rsToUse = nativeJdbcExtractor.getNativeResultSet(rs); } return rse.extractData(rsToUse); } finally { JdbcUtils.closeResultSet(rs); } } @Override public String getSql() { return sql; } } //真正执行的方法 return execute(new QueryStatementCallback());}
这里只贴出了其中一个query方法,其他的”套路”都跟它差不多,如果感兴趣的话自己可以深究一下JdbcTemplate源码
模板模式优缺点
优点:
- 抽出不变行为,对代码的重复利用;要扩展的话,只需添加子类
缺点:
- 按照我们的设计习惯,抽象类负责声明最抽象、最一般的事情属性和方法,实现类完成具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了 部分抽象方法,由子类实现,子类执行结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目中,会带来代码阅读的难度,而且也会让新手产生不适感
-
因为引入了一个抽象类,如果具体实现过多的话,需要用户或开发人员需要花更多的时间去理清类之间的关系