深圳做网站的公司的区域,建行手机银行app下载,浙江省建设厅官网证件查询,wordpress怎么添加描述martin fowler目前#xff0c;我正在阅读Martin Fowler撰写的有关DSL- 特定领域语言的精彩书籍。 围绕DSL的嗡嗡声#xff0c;围绕轻松支持DSL创建的语言#xff0c;以及DSL的使用#xff0c;使我好奇地了解和学习DSL的这一概念。 到目前为止#xff0c;这本书的使用经验令… martin fowler 目前我正在阅读Martin Fowler撰写的有关DSL- 特定领域语言的精彩书籍。 围绕DSL的嗡嗡声围绕轻松支持DSL创建的语言以及DSL的使用使我好奇地了解和学习DSL的这一概念。 到目前为止这本书的使用经验令人印象深刻。 马丁·福勒Martin Fowler在他的书中提到的DSL定义 特定领域的语言名词一种表达能力有限的计算机编程语言专注于特定领域。 DSL并不是什么新鲜事物它已经存在了很长时间。 人们使用XML作为DSL的一种形式。 使用XML作为DSL很容易因为我们有XSD来验证DSL有解析器来解析DSL还有XSLT来将DSL转换成其他语言。 而且大多数语言为解析XML和填充其域模型对象提供了很好的支持。 诸如RubyGroovy等语言的出现增加了DSL的采用。 例如使用Ruby编写的Web框架Rails广泛使用DSL。 Martin Fowler在他的书中将DSL分为内部外部和语言工作台。 当我阅读了内部DSL概念时我使用Java作为宿主语言在自己的简单DSL上玩了一些。 内部DSL驻留在宿主语言中并受宿主语言的语法功能约束。 使用Java作为宿主语言并不能给我真正清晰的DSL但我已尽力使其更接近可以舒适地理解DSL的形式。 我试图创建用于创建图形的DSL。 据我所知输入和表示图形的不同方法是 邻接表和邻接矩阵 。 我一直发现这很难使用尤其是在Java这样的语言中这些语言没有矩阵作为一等公民。 在这里我试图创建一个内部DSL以用Java填充图形。 马丁·福勒Martin Fowler在他的书中强调需要保持语义模型与DSL不同并引入一种中间表达构建器该构建器可以从DSL填充语义模型。 通过保持这一点我能够通过编写不同的DSL语法和表达式生成器并同时使用相同的语义模型来实现3种不同形式的DSL。 了解语义模型 在这种情况下语义模型是Graph类它包含Edge实例的列表每个Edge包含从Vertex到Vertex以及权重。 让我们看一下相同的代码 Graph.java import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;public class Graph {private ListEdge edges;private SetVertex vertices;public Graph() {edges new ArrayList();vertices new TreeSet();}public void addEdge(Edge edge){getEdges().add(edge);}public void addVertice(Vertex v){getVertices().add(v);}public ListEdge getEdges() {return edges;}public SetVertex getVertices() {return vertices;}public static void printGraph(Graph g){System.out.println(Vertices...);for (Vertex v : g.getVertices()) {System.out.print(v.getLabel() );}System.out.println();System.out.println(Edges...);for (Edge e : g.getEdges()) {System.out.println(e);}}
} Edge.java public class Edge {private Vertex fromVertex;private Vertex toVertex;private Double weight;public Edge() {}public Edge(Vertex fromVertex, Vertex toVertex, Double weight) {this.fromVertex fromVertex;this.toVertex toVertex;this.weight weight;}Overridepublic String toString() {return fromVertex.getLabel() to toVertex.getLabel() with weight getWeight();}public Vertex getFromVertex() {return fromVertex;}public void setFromVertex(Vertex fromVertex) {this.fromVertex fromVertex;}public Vertex getToVertex() {return toVertex;}public void setToVertex(Vertex toVertex) {this.toVertex toVertex;}public Double getWeight() {return weight;}public void setWeight(Double weight) {this.weight weight;}
} 顶点 public class Vertex implements ComparableVertex {private String label;public Vertex(String label) {this.label label.toUpperCase();}Overridepublic int compareTo(Vertex o) {return (this.getLabel().compareTo(o.getLabel()));}public String getLabel() {return label;}public void setLabel(String label) {this.label label;}
} 现在我们已经有了语义模型让我们构建DLS。 您应该注意我不会更改语义模型。 语义模型不应该改变不是硬性规定而是可以通过添加用于获取数据或修改数据的新API来发展语义模型。 但是将语义模型紧密绑定到DSL并不是一个好的方法。 将它们分开可以帮助独立测试语义模型和DSL。 Martin Fowler提出的创建内部DSL的不同方法是 方法链接 功能顺序 嵌套函数 Lambda表达式/闭包 除了功能序列我已经在本文中说明了3。 但是我在使用Closures / Lambda表达式时使用了Functional Sequence方法。 通过方法链接实现内部DSL 我设想我的DSL是这样的 Graph().edge().from(a).to(b).weight(12.3).edge().from(b).to(c).weight(10.5) 为了实现这种DSL的创建我们将必须编写一个表达式生成器该表达式生成器允许弹出语义模型并提供使创建DSL 流畅的接口 。 我创建了2个表达式构建器-一个用于构建完整的Graph另一个用于构建单个边。 在构建Graph / Edge的过程中这些表达式生成器保存中间的Graph / Edge对象。 通过在这些表达式生成器中创建静态方法然后使用静态导入在DSL中使用它们可以实现上述语法。 Graph()开始填充Graph模型而edge()及其后的一系列方法 from() to() weight()填充Edge模型。 edge()也会填充Graph模型。 让我们看一下GraphBuilder它是用于填充Graph模型的表达式构建器。 GraphBuilder.java public class GraphBuilder {private Graph graph;public GraphBuilder() {graph new Graph();}//Start the Graph DSL with this method.public static GraphBuilder Graph(){return new GraphBuilder();}//Start the edge building with this method.public EdgeBuilder edge(){EdgeBuilder builder new EdgeBuilder(this);getGraph().addEdge(builder.edge);return builder;}public Graph getGraph() {return graph;}public void printGraph(){Graph.printGraph(graph);}
} 还有EdgeBuilder它是用于填充Edge模型的表达式生成器。 EdgeBuilder.java public class EdgeBuilder {Edge edge;//Keep a back reference to the Graph Builder.GraphBuilder gBuilder;public EdgeBuilder(GraphBuilder gBuilder) {this.gBuilder gBuilder;edge new Edge();}public EdgeBuilder from(String lbl){Vertex v new Vertex(lbl);edge.setFromVertex(v);gBuilder.getGraph().addVertice(v);return this;}public EdgeBuilder to(String lbl){Vertex v new Vertex(lbl);edge.setToVertex(v);gBuilder.getGraph().addVertice(v);return this;}public GraphBuilder weight(Double d){edge.setWeight(d);return gBuilder;}} 让我们尝试一下DSL public class GraphDslSample {public static void main(String[] args) {Graph().edge().from(a).to(b).weight(40.0).edge().from(b).to(c).weight(20.0).edge().from(d).to(e).weight(50.5).printGraph();Graph().edge().from(w).to(y).weight(23.0).edge().from(d).to(e).weight(34.5).edge().from(e).to(y).weight(50.5).printGraph();}
} 输出将是 Vertices...
A B C D E
Edges...
A to B with weight 40.0
B to C with weight 20.0
D to E with weight 50.5
Vertices...
D E W Y
Edges...
W to Y with weight 23.0
D to E with weight 34.5
E to Y with weight 50.5 您是否发现此方法比“邻接表/邻接矩阵”方法更易于阅读和理解 这种方法链接类似于我不久前写的Train Wreck模式 。 嵌套功能的内部DSL 在嵌套函数方法中DSL的样式不同。 在这种方法中我会将函数嵌套在函数中以填充语义模型。 就像是 Graph(edge(from(a), to(b), weight(12.3),edge(from(b), to(c), weight(10.5)
); 这种方法的优点是它的层次结构自然不同于方法链接在方法链中我不得不以不同的方式设置代码格式。 而且这种方法不会在“表达式”构建器中保持任何中间状态即在解析/执行DSL时表达式构建器不保存Graph和Edge对象。 语义模型与此处讨论的相同。 让我们看一下此DSL的表达式构建器。 NestedGraphBuilder.java //Populates the Graph model.
public class NestedGraphBuilder {public static Graph Graph(Edge... edges){Graph g new Graph();for(Edge e : edges){g.addEdge(e);g.addVertice(e.getFromVertex());g.addVertice(e.getToVertex());}return g;}} NestedEdgeBuilder.java //Populates the Edge model.
public class NestedEdgeBuilder {public static Edge edge(Vertex from, Vertex to, Double weight){return new Edge(from, to, weight);}public static Double weight(Double value){return value;}} NestedVertexBuilder.java //Populates the Vertex model.
public class NestedVertexBuilder {public static Vertex from(String lbl){return new Vertex(lbl);}public static Vertex to(String lbl){return new Vertex(lbl);}
} 如果您已经观察到上面定义的表达式构建器中的所有方法都是静态的。 我们在代码中使用静态导入来创建我们开始构建的DSL。 注意我对表达式构建器语义模型和dsl使用了不同的软件包。 因此请根据您使用的软件包名称更新导入。 //Update this according to the package name of your builder
import static nestedfunction.NestedEdgeBuilder.*;
import static nestedfunction.NestedGraphBuilder.*;
import static nestedfunction.NestedVertexBuilder.*;/**** author msanaull*/
public class NestedGraphDsl {public static void main(String[] args) {Graph.printGraph(Graph(edge(from(a), to(b), weight(23.4)),edge(from(b), to(c), weight(56.7)),edge(from(d), to(e), weight(10.4)),edge(from(e), to(a), weight(45.9))));}
} 输出为 Vertices...
A B C D E
Edges...
A to B with weight 23.4
B to C with weight 56.7
D to E with weight 10.4
E to A with weight 45.9 现在来了有趣的部分如何在DSL中利用即将到来的lambda表达式支持。 使用Lambda表达式的内部DSL 如果您想知道Lambda表达式在Java中的作用请在此花一些时间然后再继续进行操作。 在本示例中我们还将坚持此处描述的相同语义模型。 该DSL利用功能序列以及使用lambda表达式支持。 让我们看看我们如何希望最终的DSL像这样 Graph(g - {g.edge( e - {e.from(a);e.to(b);e.weight(12.3);});g.edge( e - {e.from(b);e.to(c);e.weight(10.5);});}
) 是的我知道上面的DSL充满了标点符号但是我们必须忍受它。 如果您不喜欢它那么可能会选择其他语言。 在这种方法中我们的表达式构建器应接受lambda expression / closure / block然后通过执行lambda expression / closure / block填充语义模型。 此实现中的表达式生成器以通过方法链接在DSL实现中相同的方式维护Graph和Edge对象的中间状态。 让我们看一下表达式构建器 GraphBuilder.java //Populates the Graph model.
public class GraphBuilder {Graph g;public GraphBuilder() {g new Graph();}public static Graph Graph(ConsumerGraphBuilder gConsumer){GraphBuilder gBuilder new GraphBuilder();gConsumer.accept(gBuilder);return gBuilder.g;}public void edge(ConsumerEdgeBuilder eConsumer){EdgeBuilder eBuilder new EdgeBuilder();eConsumer.accept(eBuilder);Edge e eBuilder.edge();g.addEdge(e);g.addVertice(e.getFromVertex());g.addVertice(e.getToVertex());}
} EdgeBuilder.java //Populates the Edge model.
public class EdgeBuilder {private Edge e;public EdgeBuilder() {e new Edge();}public Edge edge(){return e;}public void from(String lbl){e.setFromVertex(new Vertex(lbl));}public void to(String lbl){e.setToVertex(new Vertex(lbl));}public void weight(Double w){e.setWeight(w);}} 在GraphBuilder您会看到两行突出显示的代码。 它们利用Java 8中引入的功能接口 Consumer 。 现在让我们使用上述表达式构建器来创建我们的DSL //Update the package names with the ones you have given
import graph.Graph;
import static builder.GraphBuilder.*;public class LambdaDslDemo {public static void main(String[] args) {Graph g1 Graph( g - {g.edge( e - {e.from(a);e.to(b);e.weight(12.4);});g.edge( e - {e.from(c);e.to(d);e.weight(13.4);});});Graph.printGraph(g1);}
} 输出为 Vertices...
A B C D
Edges...
A to B with weight 12.4
C to D with weight 13.4 至此我结束了这段繁重的代码。 让我知道是否您想把它吐到3个帖子中-每个DSL实现一个。 我将其放在一个地方这样可以帮助我们比较3种不同的方法。 总结一下 在这篇文章中我谈到了DSL 即 Martin Fowler在《 领域特定语言 》一书中提到的DSL。 为实现内部DSL的三种方法分别提供了一种实现 方法链接 嵌套函数 具有函数序列的Lambda表达式 参考 使用JavaJava 8创建内部DSL 8 在Experiences Unlimited博客中采用了JCG合作伙伴 Mohamed Sanaulla的Martin Fowler的方法 。 翻译自: https://www.javacodegeeks.com/2013/06/creating-internal-dsls-in-java-java-8-adopting-martin-fowlers-approach.htmlmartin fowler