模板方法是什么?
模板方法模式在一个方法中定义一个算法的骨架,将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体的结构情况下,重新定义算法中的某些步骤。
public abstract class AbstractClass {
public void templateMedhod(){
//一堆代码,通用的代码
method1();
//一堆代码,通用的代码
method2();
//一堆代码,通用的代码
method3();
}
protected abstract void method3();
protected abstract void method2();
protected abstract void method1();
}
public class ConcreteClass1 extends AbstractClass {
@Override
protected void method3() {
System.out.println("3");
}
@Override
protected void method2() {
System.out.println("2");
}
@Override
protected void method1() {
System.out.println("1");
}
}
public class ConcreteClass2 extends AbstractClass {
@Override
protected void method3() {
System.out.println("3");
}
@Override
protected void method2() {
System.out.println("2");
}
@Override
protected void method1() {
System.out.println("1");
}
}
public class client {
public static void main(String[] args) {
AbstractClass tm = new ConcreteClass1();
tm.templateMedhod();
}
}
模式很简单,就是一个抽象类(AbstractClass ),定义方法。在具体实现类中进行实现。
具体实现类可以有一个,也可以有很多个。例如代码中的(ConcreteClass1,ConcreteClass2)
从代码中,我们就能看到,模板方法模式,复用和扩展。
我们可以将通用的代码,在templateMedhod 中书写。 对于每个模块的差异,分别进行实现。
回调机制
我们在开发过程中,常常也会用到回调机制。
回调机制有两种,一种是同步回调,一种是异步回调。
a调用b,b反过来调用a,就是回调。
在c中,可以用函数指针,java中需要使用回调函数的类对象。
代码示例:
例如张三给李四打电话:
定义一个回调接口
public interface ICallBack {
void methodCallback();
}
张三
public class Zhangsan {
public static void main(String[] args) {
Zhangsan aClass = new Zhangsan();
aClass.phoneCall();
}
public void phoneCall() {
System.out.println("找到lisi");
Lisi lisi = new Lisi();
System.out.println("开始打电话");
lisi.process(new ICallBack() {
@Override
public void methodCallback() {
System.out.println("张三这也接通了");
}
});
}
}
李四
public class Lisi {
//用来处理电话
public void process(ICallBack callBack){
System.out.println("正在通话中。。。");
System.out.println("等2s种后");
try {
Thread.sleep(1000*2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("lisi接电话了");
callBack.methodCallback();
}
}
运行结果是:
找到lisi
开始打电话
正在通话中。。。
等2s种后
lisi接电话了
张三这也接通了
同步回调指在函数返回之前执行回调函数;异步回调指的是在函数返回之后执行回调函数。
上面这种是同步回调函数。
框架举例JDBCTEMPLATE:
jdbc操作数据库很繁琐。有很多步骤。
//1.创建datasource
//2.获取connection
//3.创建statement
//4 执行sql语句
//5 处理resultset
//6 关闭资源对象
当我们使用jdbctemplate的时候,直接执行excute方法就行了。只需执行两个步骤就行了。
//获取template实例
private JdbcTemplate jdbcTemplate=ioc.getBean(JdbcTemplate.class);
//执行sql语句
String sql = "select * from Order";
jdbcTemplate.execute(sql);
其他的重复步骤 封装到了框架中。
假设我们是设计者,那些重复的步骤封装。我们可以使用模板方法模式:
我们定义一个AbstractJdbcTemplate类
public abstract class AbstractJdbcTemplate{
@Autowired
private DataSource dataSource;
public final Object execute(String sql) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);
//处理结果使用模板方法
Object object = handleResultSet(resultSet);
return object;
} catch (SQLException e) {
System.out.print(e);
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
}
}
}
return null;
}
protected abstract Object handleResultSet(ResultSet rs) throws SQLException;
}
handleResultSet用来处理 ResultSet
具体实现我们使用一个类来继承AbstractJdbcTemplate
public class OrderJdbcTemplate extends AbstractJdbcTemplate{
@Override
protected Object handleResultSet(ResultSet rs) throws SQLException {
List<Order> orders = new ArrayList<Order>();
while (rs.next()) {
Order order = new Order(rs.getLong("id"), rs.getString("order_number"), rs.getString("delivery_address"));
orders.add(order);
}
return orders;
}
}
ResultSet 中的结果,并构建了业务对象进行返回。
我们再使用 OrderJdbcTemplate 执行目标 SQL 语句,如下代码所示
AbstractJdbcTemplate jdbcTemplate = new OrderJdbcTemplate();
List<Order> orders = (List<Order>) jdbcTemplate.execute("select * from Order");
如果使用模板方法模式,我们在业务代码中需要定义各种实现类,我们需要创建和维护新类。
这也就是模板方法模式的弊端,使用了继承。我们知道写代码尽量使用接口而不是继承,也就是基于接口编程。
回调机制便是基于接口实现。
那么,我们将handleStatement 改为一个接口。
public interface StatementCallback {
Object handleStatement(Statement statement) throws SQLException;
}
那么原有的AbstractJdbcTemplate 需要修改如下:
public class CallbackJdbcTemplate {
@Autowired
private DataSource dataSource;
public final Object execute(StatementCallback callback){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
Object object = callback.handleStatement(statement);
return object;
} catch (SQLException e) {
System.out.print(e);
} finally {
//省略异常处理
}
return null;
}
}
上面的
Object object = callback.handleStatement(statement);
使用了接口,这样把原来需要子类抽象的方法转嫁到了接口(StatementCallback )之上。
我们写代码的时候,就可以使用:
public Object queryOrder(final String sql) {
CallbackJdbcTemplate jdbcTemplate = new CallbackJdbcTemplate();
return jdbcTemplate.execute(new StatementCallback() {
public Object handleStatement(Statement statement) throws SQLException {
ResultSet rs = statement.executeQuery(sql);
List<Order> orders = new ArrayList<Order>();
while (rs.next()) {
Order order = new Order(rs.getLong("id"), rs.getString("order_number"),
rs.getString("delivery_address"));
orders.add(order);
}
return orders;
}
});
}