组合模式(Composite Pattern)
定义:组合模式也成为整体--部分模式,宗旨是通过将单个对象和组合对象用相同的接口进行表示。使客户端对单个对象和组合对象保持一致的方式处理。属于结构型模式。
适用场景:希望客户端可以忽略组合对象和单个对象的差异时;对象层次具备整体和部分,呈树形结构时。
委派模式(Delegate Pattern)
定义:委派模式又称委托模式,基本作用是负责任务的调度和任务分配,将任务的分配和执行分离开来,可以看做是一种特殊情况下的静态代理的全权处理。属于行为型模式,不是GOF 23种设计模式之一。
适用场景:委派对象本身不清楚如何处理一个任务,把任务交给其他对象处理。
优点:通过任务委派可以将大型任务细化,统一管理子任务,将任务分配和执行分离,避免类的臃肿。
委派模式和代理模式区别:
1) 委派模式是行为型模式,代理模式是结构型模式;
2) 委派模式注重任务分配,注重结果;代理模式注重的是功能增强,注重过程;
3) 委派模式是一种特殊的静态代理,相当于全权代理;
在源码中Method、ClassLoader、BeanDefinition、DispatcherServlet都有用到委派模式来分配任务由其他对象执行。
模板方法模式(Template Method Pattern)
定义:模板方法模式又称模板模式,是指定义一个算法的骨架,并允许子类为其中一个或多个步骤提供实现。模板模式可以使子类在不改变算法结构的情况下,重新定义算法的实现;属于行为性模式。
适用场景:一般应用于算法,将固定部分实现,将可变的行为留给子类来实现;将各子类中公共的行为提取出来集中在一个公共的父类中,从而避免代码重复。
优点:
1) 模板模式将相同处理逻辑代码抽取到抽象父类中,去除了子类重复代码,提高代码复用性;
2) 将不同的代码放在子类中,通过对子类的扩展增加新的行为,提高代码可扩展性;
缺点:
1) 每个抽象类都需要一个子类来实现,导致类数量增加,也增加了系统复杂度;
2) 如果父类添加新的抽象方法,所有子类都需要修改去实现;所以如果步骤不稳定,频繁改变不适合使用模板模式;
在spring-jdbc框架中,就用到了模板模式,JdbcTemplate中定义了连接数据库查询的框架结构和方法,而查询结果集如何映射给用户查询的entity对象,声明了一个钩子方法rowMapper.mapRow(rs, rowNumber)由调用方来自己实现:
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
return (List)result(this.query((String)sql, (ResultSetExtractor)(new RowMapperResultSetExtractor(rowMapper))));
}
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
QueryStatementCallback() {}
@Nullable
public T doInStatement(Statement stmt) throws SQLException {
ResultSet rs = null;
Object var3;
try {
rs = stmt.executeQuery(sql);
var3 = rse.extractData(rs);
} finally {
JdbcUtils.closeResultSet(rs);
}
return var3;
}
public String getSql() {
return sql;
}
}
return this.execute((StatementCallback)(new QueryStatementCallback()));
}
}
@FunctionalInterface
public interface RowMapper<T> {
@Nullable
T mapRow(ResultSet var1, int var2) throws SQLException;
}
public class RowMapperResultSetExtractor<T> implements ResultSetExtractor<List<T>> {
private final RowMapper<T> rowMapper;
private final int rowsExpected;
public List<T> extractData(ResultSet rs) throws SQLException {
List<T> results = this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList();
int var3 = 0;
while(rs.next()) {
results.add(this.rowMapper.mapRow(rs, var3++));
}
return results;
}
}