java 模板模式_java设计模式之模板模式

模板模式

模板模式(Template Pattern),定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构,只是重定义该算法的某些特定步骤。这种类型的设计模式属于行为型模式。

模板模式解决的问题

一些方法通用,却在每一个子类都重新写了这一方法,带来大量重复的代码的问题。相同的部分父类给出统一的模板,不同的部分,子类进行重写。

命令模式模式角色

AbstractTemplate(抽象类):在抽象类中定义了一系列基本操作,这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。

ConcreteTemplate(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

模板抽象类方法类型

抽象方法:在抽象类声明、由其具体子类实现。

具体方法:在抽象类中声明并实现,在具体子类中可以继承或重写。

钩子方法:在抽象类中声明并实现(可以是空的实现),子类视情况进行重写覆盖,一般是逻辑判断方法。

模板方法:定义统一模板算法的方法,提供实现方法,子类一般不需要重写。

模板模式和策略模式的区别

模板模式定义了一个统一的算法,子类可以对算法的某一些步骤,进行覆盖重写,可以提高代码的复用率。同过继承的方式实现,依赖比较强,不够灵活。策略模式每个子类都是一种实现,可以完全不相同,即便算法之间存在共性,也需要在每个子类重新实现,通过聚合的方式实现,可以动态的改变算法,比较灵活。

代码实现

/**

* 抽象模板

*/

public abstract class Game {

/**

* 具体方法

*/

public void initialize(){

System.out.println("game initialize .........");

}

/**

* 抽象方法

*/

abstract void startPlay();

abstract void endPlay();

/**

* 钩子方法

* @return 是否需要结束

*/

boolean isNeedEnd(){

return false;

}

/**

* 模板方法

* final修饰 不允许子类修改

* 每一个游戏先初始化、开始游戏 是否需要结束游戏 根据钩子进行判断

*/

public final void play(){

//初始化游戏

initialize();

//开始游戏

startPlay();

if(isNeedEnd()){

//结束游戏

endPlay();

}

}

}

/**

* 具体模板

* 足球游戏

*/

public class Football extends Game{

@Override

void endPlay() {

System.out.println("Football Game Finished!");

}

@Override

void startPlay() {

System.out.println("Football Game Started. Enjoy the game!");

}

@Override

boolean isNeedEnd() {

return false;

}

}

/**

* 模板测试类

*/

public class TemplateModeTest {

public static void main(String[] args) {

Game game = new Basketball();

game.play();

game = new Football();

game.play();

}

}

运行结果:

JDK和框架中的模板模式

public T execute(StatementCallback action) throws DataAccessException {

Assert.notNull(action, "Callback object must not be null");

Connection con = DataSourceUtils.getConnection(getDataSource());

Statement stmt = null;

try {

Connection conToUse = con;

if (this.nativeJdbcExtractor != null &&

this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {

conToUse = this.nativeJdbcExtractor.getNativeConnection(con);

}

stmt = conToUse.createStatement();

applyStatementSettings(stmt);

Statement stmtToUse = stmt;

if (this.nativeJdbcExtractor != null) {

stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);

}

T result = action.doInStatement(stmtToUse);

handleWarnings(stmt);

return result;

}

catch (SQLException ex) {

// Release Connection early, to avoid potential connection pool deadlock

// in the case when the exception translator hasn't been initialized yet.

JdbcUtils.closeStatement(stmt);

stmt = null;

DataSourceUtils.releaseConnection(con, getDataSource());

con = null;

throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);

}

finally {

JdbcUtils.closeStatement(stmt);

DataSourceUtils.releaseConnection(con, getDataSource());

}

}

public boolean isSkipResultsProcessing() {

return this.skipResultsProcessing;

}

spring中的JdbcTemplate、RedisTemplate、RestTemplate都是典型的模板模式,都是继承Accessor类和实现Operations接口。

优缺点

优点:封装不变部分,扩展可变部分。 提取公共代码,便于维护。 行为由父类控制,子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

生活中的命令模式

PPT模板,从网上下载自己喜欢的PPT模板,在不改变大的整体框架的情况下,替换掉部分内容,比如文字内容、部分图片内容,可以很大程度提高产出率。

机器学习中的迁移学习,也是一个典型的模板模式,机器学习中提供了很多模板模型,VGG19、ResNet50、InceptionV3,如果我们自己训练这个模型需要花很长的时间,几周或者更长的时间,可以把别人训练好的模型作为模板,做一些细微的调整,去训练我们自己的样本数据,得到一个适合我们特有数据的模型,只需要训练比较短的时间,就能得到一个比较好的模型。

我的启发

模板模式就像站在巨人的肩膀上,在大方向上借鉴别人的经验,进行适当的调整,以满足我们自己定制化的需求。当我们不具备造轮子的能力的时候,合理选择适合的模板也是一种不错的选择。


版权声明:本文为weixin_30711223原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。