在笔者之前一篇介绍策略模式案例II-看DBRider如何导入数据的文章中有提到为了支持某些操作的组合,在这个策略模式中还混合使用了组合模式。 首先还是通过策略模式来看一下类图。
在右下角有一个名为CompsiteOperation的类,从命名上看疑似使用了组合模式。
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
说到组合模式,一般都会用树来作为案例,树由树枝和树叶组合而成,而树枝又包含了更小的枝杈或者是树叶。由于这是一个关于结构型的设计模式,是一个比较静态的呈现,会让人感觉有些抽象,以下是笔者从知乎上面一篇文章中抠来的一张图,通过UML序列图的方式来表达组合模式,就更为直观了。
从上图我们可以看出,当客户端Client调用整个树的类CompositeA类的方法doAction()时,由于采用了组合模式,在CompositeA类中存储了以下的节点的组合
首先来看看调用者。前面有提到@DataSet注解有一个strategy属性,指定了若干的数据集插入数据库的策略,这主要是通过SeedStrategy 这个枚举类来实现的。
package com.github.database.rider.core.api.dataset;
/**
* Created by pestano on 23/07/15.
*/
import org.dbunit.operation.*;
public enum SeedStrategy {
CLEAN_INSERT(DatabaseOperation.CLEAN_INSERT),
TRUNCATE_INSERT(new CompositeOperation(DatabaseOperation.TRUNCATE_TABLE, DatabaseOperation.INSERT)),
INSERT(DatabaseOperation.INSERT),
REFRESH(DatabaseOperation.REFRESH),
UPDATE(DatabaseOperation.UPDATE);
private final DatabaseOperation operation;
SeedStrategy(DatabaseOperation operation) {
this.operation = operation;
}
public DatabaseOperation getOperation() {
return operation;
}
}
这其中有两种策略就属于组合策略,
例如CLEAN_INSERT就是先将数据库中目标表清空,然后在执行INSERT操作。
作为组合类的标志,CompositeOperation中应该包含了一个容纳DatabaseOperation类及其子类的组合,以及遍历并执行execute方法的execute方法,我们来看一下
package org.dbunit.operation;
import java.sql.SQLException;
import java.util.Arrays;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CompositeOperation extends DatabaseOperation {
private static final Logger logger = LoggerFactory.getLogger(CompositeOperation.class);
private final DatabaseOperation[] _actions;
public CompositeOperation(DatabaseOperation action1, DatabaseOperation action2) {
this._actions = new DatabaseOperation[]{action1, action2};
}
public CompositeOperation(DatabaseOperation[] actions) {
this._actions = actions;
}
public void execute(IDatabaseConnection connection, IDataSet dataSet) throws DatabaseUnitException, SQLException {
logger.debug("execute(connection={}, , dataSet={}) - start", connection, dataSet);
for(int i = 0; i < this._actions.length; ++i) {
DatabaseOperation action = this._actions[i];
action.execute(connection, dataSet);
}
}
//...
}
可以看到,在CompositeOperation类中的确有如下的一个数组
private final DatabaseOperation[] _actions;
以及一个重载的execute方法
public void execute(IDatabaseConnection connection, IDataSet dataSet)
这样,就能将_actions数组中存放的各类型DataBaseOperation按照顺序执行了。
参考之前的类图,结合DataBaseRider中的源码,笔者画了下面的一个简化示意图。如前所述,目前有两种策略是使用了组合模式,也就是是CompositeOperation类的两个实例,分别是CLEAN_INSERT和TRUNCATE_INSERT。整个组合的调用过程还是比较清晰的。
如果有看到开源项目中使用的其它设计模式,欢迎留言给笔者提供线索。