Java 8的内部DSL

13-06-03 banq
                   

DSL定义:Domain-specific language (名词,简称DSL): 是一种专注特定领域的有限表达法。

Martin Fowler 认为DSL区别于通常语义上的领域模型,通过一些内部的DSL表达式可以导入或构建领域模型。(DSL类似领域模型的Builder)。

这种内部DSL表达式有下面几种:

1. Method Chaining 方法链 Fluent Style流畅风格

2. Functional Sequence

3. Nested Functions 嵌套函数

4.Lambda Expressions/Closures

在Java 8中创建Martin Fowler的内部DSL Creating Internal DSLs in Java, Java 8- Adopting Martin Fowler’s approach | Java, JVM and beyond

一文以Java 8为例说明了这种内部表达式的使用。

下面以三个语义模型为例:

Graph

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
 
public class Graph {
 
  private List<Edge> edges;
  private Set<Vertex> 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 List<Edge> getEdges() {
    return edges;
  }
 
  public Set<Vertex> 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);
    }
  }
}
<p>

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;
  }
  
  @Override
  public 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;
  }
}
<p>

Vertex.java

ublic class Vertex implements Comparable<Vertex> {
  private String label;
 
  public Vertex(String label) {
    this.label = label.toUpperCase();
  }
   
  @Override
  public int compareTo(Vertex o) {
    return (this.getLabel().compareTo(o.getLabel()));
  }
 
  public String getLabel() {
    return label;
  }
 
  public void setLabel(String label) {
    this.label = label;
  }
}
<p>

                   

5
banq
2013-06-03 08:47

方法链是由DDD创始者Eric Evans和Martifowler共同提倡的一种流畅风格的简化代码写法,如下:

Graph()
  .edge()
    .from("a")
    .to("b")
    .weight(12.3)
  .edge()
    .from("b")
    .to("c")
    .weight(10.5)
<p>

那么如何实现这种领域模型创建的流畅简化写法呢?

首先,建立两个builder模式构建器,分别是模型Graph和edge的GraphBuilder和EdgeBuilder:

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);
  }
}

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;
  }
   
}
<p>

好了,方法链风格的代码都准备好,我们就可以使用流畅简化的风格来创建赋值模型了,客户端代码:

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();
 
  }
}
<p>

输出结果:

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 Pattern

banq
2013-06-03 09:08

如果说方法链风格内部会包含状态(属于一种有态用法),那么嵌套函数写法不再内部包含模型状态,这种表达法DSL是被分析被解释执行。

三个模型graph edge和Vertex的builder类如下:

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;
  }
   
}

/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;
  }
     
}

//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);
  }
}
<p>

嵌套函数风格的写法如下:

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))
      )
    );
     
  }
}
<p>

输出结果:

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

banq
2013-06-03 09:13

lambda写法如下:

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);
    });
     
  }
)
<p>

为了实现这个目标,创建Graph和Edge两个构造器:

//Populates the Graph model.
public class GraphBuilder {
 
  Graph g;
  public GraphBuilder() {
    g = new Graph();
  }
   
  public static Graph Graph(Consumer<GraphBuilder> gConsumer){
    GraphBuilder gBuilder = new GraphBuilder();
    gConsumer.accept(gBuilder);
    return gBuilder.g;
  }
   
//注意这个方法参数,这是java 8支持的函数参数
  public void edge(Consumer<EdgeBuilder> eConsumer){
    EdgeBuilder eBuilder = new EdgeBuilder();
    eConsumer.accept(eBuilder);
    Edge e = eBuilder.edge();
    g.addEdge(e);
    g.addVertice(e.getFromVertex());
    g.addVertice(e.getToVertex());
  }
}

//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);
  }
   
}
<p>

调用代码:

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);
  }
}
<p>

输出结果:

Vertices...

A B C D

Edges...

A to B with weight 12.4

C to D with weight 13.4

bingyang
2013-06-05 09:30

lambda表达式在.net中支持很好,而且还是延迟执行的;方法级联,序列 使得方法给人看起来很简洁、连贯

2Go 1 2 下一页