我有一个带有图形的类。我对图进行迭代并创建一个构建图的字符串,然后将其写入Java文件中。有没有更好的方法可以做到这一点,我阅读了有关JDT和CodeModel的信息,但是我确实需要一些如何使用它的提示。
编辑
我正在做一个正则表达式代码生成器,到目前为止,我已经将正则表达式转换为有向图表示的DFA(使用grail库)。当我拥有DFA时,下一步就是生成具有三个方法的类,第一个方法构建相同的图(DFA),第二个方法从一个节点移动到另一个节点,第三个方法在输入字符串被接受的情况下匹配。只有第一个方法会根据正则表达式输入进行更改,其他两个方法是静态的,并且对于每个生成的java类都是相同的。
我的基于字符串的方法看起来像:
import grail.interfaces.DirectedEdgeInterface;
import grail.interfaces.DirectedGraphInterface;
import grail.interfaces.DirectedNodeInterface;
import grail.interfaces.EdgeInterface;
import grail.iterators.EdgeIterator;
import grail.iterators.NodeIterator;
import grail.properties.GraphProperties;
import grail.setbased.SetBasedDirectedGraph;
public class ClassName {
private SetBasedDirectedGraph graph = new SetBasedDirectedGraph();
private static DirectedNodeInterface state;
private static DirectedNodeInterface currentState;
protected DirectedEdgeInterface edge;
public ClassName() {
buildGraph();
}
protected void buildGraph() {
// Creating Graph Nodes (Automaton States)
state = graph.createNode(3);
state.setProperty(GraphProperties.LABEL, "3");
state.setProperty(GraphProperties.DESCRIPTION, "null");
graph.addNode(state);
state = graph.createNode(2);
state.setProperty(GraphProperties.LABEL, "2");
state.setProperty(GraphProperties.DESCRIPTION, "null");
graph.addNode(state);
state = graph.createNode(1);
state.setProperty(GraphProperties.LABEL, "1");
state.setProperty(GraphProperties.DESCRIPTION, "Accepted");
graph.addNode(state);
state = graph.createNode(0);
state.setProperty(GraphProperties.LABEL, "0");
state.setProperty(GraphProperties.DESCRIPTION, "Initial");
graph.addNode(state);
.....
// Creating Graph Edges (Automaton Transitions)
edge = graph.createEdge(null, (DirectedNodeInterface) graph.getNode(2),
(DirectedNodeInterface) graph.getNode(1));
edge.setProperty((GraphProperties.LABEL), "0");
graph.addEdge(edge);
edge = graph.createEdge(null, (DirectedNodeInterface) graph.getNode(2),
(DirectedNodeInterface) graph.getNode(2));
edge.setProperty((GraphProperties.LABEL), "1");
graph.addEdge(edge);
edge = graph.createEdge(null, (DirectedNodeInterface) graph.getNode(1),
(DirectedNodeInterface) graph.getNode(1));
edge.setProperty((GraphProperties.LABEL), "0");
graph.addEdge(edge);
edge = graph.createEdge(null, (DirectedNodeInterface) graph.getNode(1),
(DirectedNodeInterface) graph.getNode(3));
edge.setProperty((GraphProperties.LABEL), "1");
graph.addEdge(edge);
edge = graph.createEdge(null, (DirectedNodeInterface) graph.getNode(0),
(DirectedNodeInterface) graph.getNode(1));
edge.setProperty((GraphProperties.LABEL), "0");
graph.addEdge(edge);
edge = graph.createEdge(null, (DirectedNodeInterface) graph.getNode(0),
(DirectedNodeInterface) graph.getNode(2));
edge.setProperty((GraphProperties.LABEL), "1");
graph.addEdge(edge);
}
}
另一种解决方案是继续使用当前技术,但在builder pattern中提供一小层。要实施构建器,您只需花费一小笔时间,但可以获得更好的可读性代码。
我实现了代码的第一部分。使用适当的构建器,您可以编写:
graph = new GraphBuilder()
.createNode(3).setLabel("3").setDescription("null").add()
.createNode(2).setLabel("2").setDescription("null").add()
.createNode(1).setLabel("1").setDescription("Accepted").add()
.createNode(0).setLabel("0").setDescription("Initial").add()
// unimplemented start
.createEdge(2, 1).setLabel("0").add()
.createEdge(2, 2).setLabel("1").add()
.createEdge(1, 1).setLabel("0").add()
.createEdge(1, 3).setLabel("1").add()
.createEdge(0, 1).setLabel("0").add()
.createEdge(0, 2).setLabel("1").add()
// unimplemented end
.build();
更具可读性,不是吗?为此,您需要两个构建器。首先是GraphBuilder:
package at.corba.test.builder;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Builder for generating graphs.
* @author ChrLipp
*/
public class GraphBuilder {
/** List of StateBuilder, accesable via nodeNumber. */
Map<Integer, StateBuilder> stateBuilderMap = new LinkedHashMap<Integer, StateBuilder>();
/**
* Delegates node-specific building to NodeBuilder.
* @param nodeNumber Number of node to create
* @return NodeBuilder for the node instance to create.
*/
public StateBuilder createNode(final int nodeNumber) {
StateBuilder builder = new StateBuilder(this);
stateBuilderMap.put(nodeNumber, builder);
return builder;
}
/**
* Builder function to initialise the graph.
*/
public SetBasedDirectedGraph build() {
SetBasedDirectedGraph graph = new SetBasedDirectedGraph();
for (int key : stateBuilderMap.keySet()) {
StateBuilder builder = stateBuilderMap.get(key);
State state = graph.createNode(key);
state = builder.build(state);
graph.addNode(state);
}
return graph;
}
}
并且比StateBuilder:
package at.corba.test.builder;
import java.util.HashMap;
import java.util.Map;
/**
* Builder for generating states.
* @author ChrLipp
*/
public class StateBuilder {
/** Parent builder */
private final GraphBuilder graphBuilder;
/** Properties for this node */
Map<GraphProperties, String> propertyMap = new HashMap<GraphProperties, String>();
/**
* ctor.
* @param graphBuilder Link to parent builder
* @param nodeNumber Node to create
*/
public StateBuilder(final GraphBuilder graphBuilder) {
this.graphBuilder = graphBuilder;
}
/**
* Property setter for property Label.
* @param label value for property label
* @return current NodeBuilder instance for method chaining
*/
public StateBuilder setLabel(final String label) {
propertyMap.put(GraphProperties.LABEL, label);
return this;
}
/**
* Property setter for description Label.
* @param description value for description label
* @return current NodeBuilder instance for method chaining
*/
public StateBuilder setDescription(final String description) {
propertyMap.put(GraphProperties.DESCRIPTION, description);
return this;
}
/**
* DSL function to close the node section and to return control to the parent builder.
* @return
*/
public GraphBuilder add() {
return graphBuilder;
}
/**
* Builder function to initialise the node.
* @return newly generated node
*/
public State build(final State state) {
for (GraphProperties key : propertyMap.keySet()) {
String value = propertyMap.get(key);
state.setProperty(key, value);
}
return state;
}
}
您将对边缘执行相同的操作,但是我没有实现此:-)。在Groovy中,创建构建器更加容易(我的实现是用Java编写的构建器),例如,请参见Make a builder。
以下博客提供了一个非常简单的示例:
Java中更好的代码生成器...... ANTLR之类的工具,这是一种现代工具,专门为实现带有代码生成支持的词法分析器/解析器而创建。它具有出色的文档,包括两本书:
对这个问题还是有点模糊,但是这里有一些建议:
我在几个需要代码生成的项目(例如消息的编码/解码类)中使用了鲜为人知的产品FreeMarker。这是基于Java的解决方案,您可以在其中生成内存模型并将其提供给模板。从他们的主页: