テンプレート モードの長所と短所:
-
アドバンテージ
- テンプレート メソッドを使用して、同じ処理ロジックのコードを抽象親クラスに配置すると、コードの再利用性が向上します。
- 異なるコードを異なるサブクラスに配置し、サブクラスを拡張して新しい動作を追加してコードのスケーラビリティを向上させます。
-
欠点がある
- 各抽象クラスは実装するサブクラスを必要とするため、クラスの数が増加し、間接的にシステム実装の複雑さが増加します。
- 継承関係には独自の欠点があり、親クラスが新しい抽象メソッドを追加すると、すべてのサブクラスでそれを変更する必要があります。
以下の 2 つの例を使用してテンプレート モードを説明します。
- 1. 仕事を終えて帰宅したら食事をする 仕事を終えてから食事する時間は変わりませんが、帰宅の交通手段(バス、地下鉄、自転車)は大きく変わります。
- 2. データベース JDB テンプレート クエリ
1. 仕事帰りに食事するサンプルコード
//抽象类,实现了不变的部分和执行顺序
public abstract class GoHome {
//模版方法,规则了执行顺序,以及子类要实现的逻辑
public void execute(){
offWork();
traffic();
eat();
}
protected final void offWork(){
System.out.println("下班...");
}
//抽象方法,由子类去实现
public abstract void traffic();
public void eat(){
System.out.println("吃饭");
}
}
//公交回家子类
public class TransitGoHome extends GoHome{
@Override
public void traffic() {
System.out.println("公交回家");
}
}
//地铁回家子类
public class MetroGoHome extends GoHome{
@Override
public void traffic() {
System.out.println("地铁回家");
}
}
//测试类
public class TestMain {
public static void main(String[] args) {
GoHome xiaoming = new TransitGoHome();
System.out.println("xiaoming...");
xiaoming.execute();
System.out.println("");
GoHome zhangsan = new MetroGoHome();
System.out.println("zhangsan...");
zhangsan.execute();
}
}
mainメソッドを実行する
2. データベース JDB テンプレート クエリ
//1.定义回调接口
public interface ResultSetHandler<T> {
public T handle(ResultSet rs);
}
//2.模版方法和使用
public class SimpleJdbcTemplate {
public static void main(String[] args) {
SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate();
//用匿名内部类自行处理查询结果
List list = jdbcTemplate.query("select * from test", new ResultSetHandler<List>() {
@Override
public List handle(ResultSet rs) {
try {
//自定义处理查询结果
return convertList(rs);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
});
}
/**
* 执行查询方法
* @param queryString
* @param resultSetHandler
* @param <T>
* @return
*/
public <T> T query(String queryString, ResultSetHandler<T> resultSetHandler){
try {
//获取connection和执行sql是不变的部分
Connection connection = getConnection();
//执行sql,获取结果集
ResultSet resultSet = getResultSet(queryString, connection);
//把变化的部分用回调的方式让客户端自行处理
return resultSetHandler.handle(resultSet);
}catch (SQLException e){
e.printStackTrace();
}
return null;
}
/**
* 获取数据库connection
* @return
* @throws SQLException
*/
private static Connection getConnection() throws SQLException {
String url = "";
String username = "";
String password = "";
final Connection connection = DriverManager.getConnection(url, username, password);
return connection;
}
/**
* 执行sql,获取结果集
* @param queryString
* @param connection
* @return
* @throws SQLException
*/
private static ResultSet getResultSet(String queryString, Connection connection) throws SQLException {
PreparedStatement statement = connection.prepareStatement(queryString);
ResultSet resultSet = statement.executeQuery();
return resultSet;
}
/**
* 将ResultSet结果集转换为List
* @param rs
* @return
* @throws SQLException
*/
private static List convertList(ResultSet rs) throws SQLException{
List list = new ArrayList();
ResultSetMetaData md = rs.getMetaData();//获取键名
int columnCount = md.getColumnCount();//获取行的数量
while (rs.next()) {
Map rowData = new HashMap();//声明Map
for (int i = 1; i <= columnCount; i++) {
rowData.put(md.getColumnName(i), rs.getObject(i));//获取键名及值
}
//可多接受一个Class<T> clazz参数,将map转为指定的clazz对象
list.add(rowData);
}
return list;
}
}