Skip to content

Instantly share code, notes, and snippets.

@haiiro-shimeji
Last active December 16, 2015 22:29
Show Gist options
  • Select an option

  • Save haiiro-shimeji/5507517 to your computer and use it in GitHub Desktop.

Select an option

Save haiiro-shimeji/5507517 to your computer and use it in GitHub Desktop.
子どもとして持てるノードタイプを型として定義可能なツリー構造が作りたかった
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
/**
* 子どもとして持てるノードタイプを型として定義可能なツリー構造が作りたかった
*/
public class Test1 {
private static class Tree {
static class Node {
List<Node> children = new ArrayList<Node>();
}
static class RestrictedNode<T extends Node> extends Node {
RestrictedNode<T> append(T node, T... more) {
children.add(node);
children.addAll(Arrays.asList(more));
return this;
}
}
static class FreeNode extends RestrictedNode<Node> {}
static public class NodeType1 extends FreeNode {}
//NodeType2 can include NodeType3
static public class NodeType2 extends RestrictedNode<NodeType3> {}
static public class NodeType3 extends FreeNode {}
}
Tree.NodeType1 nodeType1() {
return new Tree.NodeType1();
}
Tree.NodeType2 nodeType2() {
return new Tree.NodeType2();
}
Tree.NodeType3 nodeType3() {
return new Tree.NodeType3();
}
@Test
public void test() {
nodeType1().append(
nodeType1().append(
nodeType2(),
nodeType3().append(
nodeType1()
)
),
nodeType2().append(
//nodeType1(), //compilation error.
//nodeType2(), //compilation error.
nodeType3()
),
nodeType3()
);
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
/**
* ノードの生成にBuilderが使いたくなったがだめだった
*/
public class Test2 {
static class Tree {
private static class Node {
List<Node> children = new ArrayList<Node>();
Map<String, String> attributes = new HashMap<String, String>();
}
static class RestrictedNode<T extends Node> extends Node {
RestrictedNode<T> append(NodeBuilder<T> builder, NodeBuilder<T>... more) {
children.add(builder.build());
for (NodeBuilder<T> b: more) {
children.add(b.build());
}
return this;
}
}
static class FreeNode extends RestrictedNode<Node> {}
static public class NodeType1 extends FreeNode {}
//NodeType2 can include NodeType3
static public class NodeType2 extends RestrictedNode<NodeType3> {}
static public class NodeType3 extends FreeNode {}
static public class NodeBuilder<T extends Node> {
final T node;
public NodeBuilder(T node) {
this.node = node;
}
public NodeBuilder<T> attr(String name, String value) {
node.attributes.put(name, value);
return this;
}
public NodeBuilder<T> append(NodeBuilder<? extends Node> builder, NodeBuilder<? extends Node>... more) {
node.append(builder, more); //アカン
return this;
}
T build() {
return node;
}
}
}
Tree.NodeBuilder<Tree.NodeType1> nodeType1() {
return new Tree.NodeBuilder(new Tree.NodeType1());
}
Tree.NodeBuilder<Tree.NodeType2> nodeType2() {
return new Tree.NodeBuilder(new Tree.NodeType2());
}
Tree.NodeBuilder<Tree.NodeType3> nodeType3() {
return new Tree.NodeBuilder(new Tree.NodeType3());
}
@Test
public void test() {
nodeType1()
.attr("hoge", "fuga")
.append(
nodeType1()
.attr("hoge", "fuga")
.append(
nodeType2(),
nodeType3().append(
nodeType1()
)
),
nodeType2().append(
nodeType1(), //コンパイルエラーにならない
nodeType2(), //コンパイルエラーにならない
nodeType3()
),
nodeType3()
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment