测试工具中的设计模式-组合模式-DBRider

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

image.png

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

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

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

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

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。整个组合的调用过程还是比较清晰的。


image.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351