概念
策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。 策略模式: 定义了一族算法; 封装了每个算法; 这族的算法可互换代替
——Wikipedia
需求
设计一个 Sorter 类,可以根据不同的比较策略对对象进行排序。
比如现在有一个 Cat 类数组,我需要根据 Cat 类的 weight 属性对 Cat 数组进行排序。
Code
Cat.java
public class Cat{
int weight, height;
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
Sorter.java
public class Sorter<T> {
public void sort(T[] arr, Comparator<T> comparator) {
for(int i=0; i<arr.length - 1; i++) {
int minPos = i;
for(int j=i+1; j<arr.length; j++) {
minPos = comparator.compare(arr[j],arr[minPos])==-1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
Comparator.java
comparator 接口的不同实现就可以理解为不同的比较策略
@FunctionalInterface
public interface Comparator<T>
Main.java
public class Main {
public static void main(String[] args) {
Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
Sorter<Cat> sorter = new Sorter<>();
//Lambda表达式实现Comparator接口
sorter.sort(a, (o1, o2) -> {
if (o1.weight < o2.weight) return -1;
else if (o1.weight > o2.weight) return 1;
else return 0;
});
System.out.println(Arrays.toString(a));
}
}
Spirng JdbcTemplate 中使用不同策略来处理结果集
Spring 版本为:1.0-m1
public void doWithResultSetFromPreparedQuery(PreparedStatementCreator psc, ResultSetExtractor rse) throws DataAccessException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DataSourceUtils.getConnection(this.dataSource);
ps = psc.createPreparedStatement(con);
if (logger.isInfoEnabled())
logger.info("Executing SQL query using PreparedStatement: [" + psc + "]");
rs = getQueryExecutor().executeQuery(ps);
// 处理结果集 ResultSet rs
rse.extractData(rs);
SQLWarning warning = ps.getWarnings();
rs.close();
ps.close();
throwExceptionOnWarningIfNotIgnoringWarnings(warning);
}
catch (SQLException ex) {
if (rs != null) {
try {
rs.close();
}
catch (SQLException ignore) {}
}
if (ps != null) {
try {
ps.close();
}
catch (SQLException ignore) {}
}
throw getExceptionTranslator().translate("JdbcTemplate.query(psc) with PreparedStatementCreator [" + psc + "]", null, ex);
}
finally {
DataSourceUtils.closeConnectionIfNecessary(con, this.dataSource);
}
}
rse.extractData(rs);
这行代码是处理结果集。ResultSetExtractor 是一个接口。
public interface ResultSetExtractor {
void extractData(ResultSet rs) throws SQLException;
}
不同的子类可以有不同的处理 rs 的策略。比如 RowCallbackHandlerResultSetExtractor 类的实现如下所示:
public void extractData(ResultSet rs) throws SQLException {
while (rs.next()) {
this.callbackHandler.processRow(rs);
}
}
总结
策略模式高内聚了不变的流程,将变化的流程抽象为策略接口。即封装不变,暴露变化。