构建有向循环图的流畅界面?
Fluent Interface to Build a Directed Cyclic Graph?
我在JUNG's DirectedSparseGraphclass的基础上创建了一组classes来表示一个有向循环图来表示BPM流程,它只提供了基本的图形操作方法来添加并找到顶点和边。
我面临的挑战是创建一个 builder that provides a fluent interface 能够创建包含复杂分支、循环和多个端节点的图形(参见下面的示例)。
平行分支
合并分支
周期
复杂
我当前的实现(参见下面的示例)正在对发生分叉的顶点使用别名(例如,Parallel Branches 中的顶点 "B"),然后我在添加该顶点的新分支。我的构建器还包括一些类似的东西,以允许合并分支和循环。引入别名是因为顶点名称在 BPM 图中不是唯一的。我想要一个更优雅流畅的界面来快速构建图形,而不需要那些引用。
Graph graph = GraphBuilder.newGraph()
.addVertex("A")
.edgeName("")
.addVertex("B", "b-fork")
.edgeName("")
.addVertex("C")
.edgeName("")
.addVertex("E")
.addBranch("b-fork")
.edgeName("")
.addVertex("D")
.edgeName("")
.addVertex("F")
.build();
问题在于构建器是一系列方法,而您想构建一个带有循环的图形。您需要回溯,为此有必要明确(使用它们的标签)或隐含地引用先前的节点,例如:
Graph graph = GraphBuilder.newGraph()
.addVertex("A")
.edgeName("")
.addVertex("B", "b-fork")
.edgeName("")
.addVertex("C")
.edgeName("")
.addVertex("E")
.goBack(2) // even worse than using label: breaks easily
.edgeName("")
.addVertex("D")
.edgeName("")
.addVertex("F")
.build();
您可以使用树结构来构建图表:
SubGraph.node("id", "label")
.to("edgeName1", SubGraph.node("A").to("", SubGraph.node("C"))),
.to("edgeName2", SubGraph.node("B"));
但这只会延迟问题的出现,因为当循环开始发挥作用时,您将再次需要明确地引用节点。缺少某种 GUI 或广泛的 ASCII 绘图,无法定义没有别名的图形。
我个人会推荐 DOT 风格的解析器:
parse("a -> b -> c -> f -> e; f -> d -> b"); // "Cyclic graph"
更易于阅读和输入。
编辑:对于 lulz:没有别名的循环图:
// do not ever do this:
GraphBuilder.parseASCII(
" -->C-- \n" +
" | v \n" +
"A-->B F-->E \n" +
" | ^ \n" +
" -->D-- \n");
您可以通过以下方式稍微减少解析:
Graph graph = GraphBuilder.newGraph()
.add("a,b,c,f,e")
.add("f,d,b");
我在JUNG's DirectedSparseGraphclass的基础上创建了一组classes来表示一个有向循环图来表示BPM流程,它只提供了基本的图形操作方法来添加并找到顶点和边。
我面临的挑战是创建一个 builder that provides a fluent interface 能够创建包含复杂分支、循环和多个端节点的图形(参见下面的示例)。
平行分支
合并分支
周期
复杂
我当前的实现(参见下面的示例)正在对发生分叉的顶点使用别名(例如,Parallel Branches 中的顶点 "B"),然后我在添加该顶点的新分支。我的构建器还包括一些类似的东西,以允许合并分支和循环。引入别名是因为顶点名称在 BPM 图中不是唯一的。我想要一个更优雅流畅的界面来快速构建图形,而不需要那些引用。
Graph graph = GraphBuilder.newGraph()
.addVertex("A")
.edgeName("")
.addVertex("B", "b-fork")
.edgeName("")
.addVertex("C")
.edgeName("")
.addVertex("E")
.addBranch("b-fork")
.edgeName("")
.addVertex("D")
.edgeName("")
.addVertex("F")
.build();
问题在于构建器是一系列方法,而您想构建一个带有循环的图形。您需要回溯,为此有必要明确(使用它们的标签)或隐含地引用先前的节点,例如:
Graph graph = GraphBuilder.newGraph()
.addVertex("A")
.edgeName("")
.addVertex("B", "b-fork")
.edgeName("")
.addVertex("C")
.edgeName("")
.addVertex("E")
.goBack(2) // even worse than using label: breaks easily
.edgeName("")
.addVertex("D")
.edgeName("")
.addVertex("F")
.build();
您可以使用树结构来构建图表:
SubGraph.node("id", "label")
.to("edgeName1", SubGraph.node("A").to("", SubGraph.node("C"))),
.to("edgeName2", SubGraph.node("B"));
但这只会延迟问题的出现,因为当循环开始发挥作用时,您将再次需要明确地引用节点。缺少某种 GUI 或广泛的 ASCII 绘图,无法定义没有别名的图形。
我个人会推荐 DOT 风格的解析器:
parse("a -> b -> c -> f -> e; f -> d -> b"); // "Cyclic graph"
更易于阅读和输入。
编辑:对于 lulz:没有别名的循环图:
// do not ever do this:
GraphBuilder.parseASCII(
" -->C-- \n" +
" | v \n" +
"A-->B F-->E \n" +
" | ^ \n" +
" -->D-- \n");
您可以通过以下方式稍微减少解析:
Graph graph = GraphBuilder.newGraph()
.add("a,b,c,f,e")
.add("f,d,b");