一、概念
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
二、基本内容
- 1、父类抽象出子类共有的方法,并自己实现他
- 2、子类实现各自不同的业务
- 3、父类实现的方法按照一定逻辑调用抽象方法
- 4、为了防止子类重写父类的方法,父类定义为final方法
三、在父类中增加钩子
- (1)可以让子类实现算法中可选的部分
- (2)在钩子对于子类的实现并不重要的时候,子类可以对此钩子置之不理
- (3)可以让子类能够有机会对模板方法中某些即将发生的步骤做出反应
四、案例
(1)定义抽象父类
public abstract class AbstractClass {
/**
* 模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作
* 声明为final,防止子类重写
*/
final void templateMethod(){
primitiveOperation1();
primitiveOperation2();
concreteOperation();
}
/**
* 抽象行为放到子类实现
*/
abstract void primitiveOperation1();
abstract void primitiveOperation2();
/**
* 钩子方法,子类可通过需求选择是否进行重写
*/
void concreteOperation(){
}
}
(2) 定义子类
public class ConcreteClassA extends AbstractClass {
@Override
void primitiveOperation1() {
System.out.println("实现A中的操作1");
}
@Override
void primitiveOperation2() {
System.out.println("实现A中的操作2");
}
@Override
void concreteOperation() {
System.out.println("钩子方法,A中可实现自己的内容");
}
}
public class ConcreteClassB extends AbstractClass {
@Override
void primitiveOperation1() {
System.out.println("实现B中的操作1");
}
@Override
void primitiveOperation2() {
System.out.println("实现B中的操作2");
}
@Override
void concreteOperation() {
System.out.println("钩子方法,B中可实现自己的内容");
}
}
(3)测试调用
public static void main(String[] args) {
AbstractClass a = new ConcreteClassA();
a.templateMethod();
AbstractClass b = new ConcreteClassB();
b.templateMethod();
}
五、类图
六、应用场景
- InputStream
其中的read()方法,由子类实现
被read(byte b[], int off, int len)模板方法调用
abstract int read()
- JUC中的AQS
acquire相当于模板方法,tryAcquire相当于基本方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- JdbcTemplate
execute 相当于模板方法,doInStatement()相当于基本方法,由子类实现
@Override
@Nullable
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(obtainDataSource());
Statement stmt = null;
try {
stmt = con.createStatement();
applyStatementSettings(stmt);
T result = action.doInStatement(stmt);
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.
String sql = getSql(action);
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("StatementCallback", sql, ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
七、和策略模式比较
- 策略模式:
- 使用组合方式,让客户选择算法实现
- 定义不同的算法,可以互换
- 模板方法:
- 使用继承方式,子类自己实现算法
- 定义了算法步骤,具体的实现延迟到子类