2个表 遍历 组合_测试工具中的设计模式之组合模式

在笔者之前一篇介绍策略模式案例II-看DBRider如何导入数据的文章中有提到为了支持某些操作的组合,在这个策略模式中还混合使用了组合模式。
首先还是通过策略模式来看一下类图。

7c2fd7ed189d618973df178e32319ffb.png

image.png

在右下角有一个名为CompsiteOperation的类,从命名上看疑似使用了组合模式。

简单了解一下组合模式Composite Pattern

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

说到组合模式,一般都会用树来作为案例,树由树枝和树叶组合而成,而树枝又包含了更小的枝杈或者是树叶。由于这是一个关于结构型的设计模式,是一个比较静态的呈现,会让人感觉有些抽象,以下是笔者从知乎上面一篇文章中抠来的一张图,通过UML序列图的方式来表达组合模式,就更为直观了。

cf4a178896fded1f46ec47e805c0da85.png

image.png

从上图我们可以看出,当客户端Client调用整个树的类CompositeA类的方法doAction()时,由于采用了组合模式,在CompositeA类中存储了以下的节点的组合

  • CompositeB

  • LeafC
    因此,CompositeA在执行doAction方法的过程会依次调用它们各自的doAction方法。
    类似的,CompositeB中也持有2个节点

  • LeafA

  • LeafB
    它们各自的doAction方法会被调用。这样,通过组合模式,只要通过CompositeA,就可以把一连串的doAction动作组合起来供客户端调用。在这个基础上,我们还可以根据业务需要派生出CompositeC等不同的组合。

为什么说CompsiteOperation是采用了组合模式。

首先来看看调用者。前面有提到@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(DatabaseOperation.CLEAN_INSERT),

  • TRUNCATE_INSERT(new CompositeOperation(DatabaseOperation.TRUNCATE_TABLE, DatabaseOperation.INSERT))

例如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按照顺序执行了。

CompositeOperation的UML序列图

参考之前的类图,结合DataBaseRider中的源码,笔者画了下面的一个简化示意图。如前所述,目前有两种策略是使用了组合模式,也就是是CompositeOperation类的两个实例,分别是CLEAN_INSERT和TRUNCATE_INSERT。整个组合的调用过程还是比较清晰的。

76d94301fa0e12cb17cdbdeb0657a59a.png

image.png

如果有看到开源项目中使用的其它设计模式,欢迎留言给笔者提供线索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值