Skip to content

Instantly share code, notes, and snippets.

@RayStarkMC
Created November 7, 2020 09:19
Show Gist options
  • Save RayStarkMC/b14e9139ccde8bd025d22fd21a64b9bf to your computer and use it in GitHub Desktop.
Save RayStarkMC/b14e9139ccde8bd025d22fd21a64b9bf to your computer and use it in GitHub Desktop.
Visitorパターンの2変数以上への拡張
public class TypesafeBinaryVisitorSample {
public static abstract class Type implements Acceptor {
private Type(){}
public static final class Type1 extends Type {
@Override
public <R> R accept(Visitor1<R> visitor1) {
return visitor1.visit(this);
}
}
public static final class Type2 extends Type {
@Override
public <R> R accept(Visitor1<R> visitor1) {
return visitor1.visit(this);
}
}
public static final class Type3 extends Type {
@Override
public <R> R accept(Visitor1<R> visitor1) {
return visitor1.visit(this);
}
}
}
interface Acceptor {
<R> R accept(Visitor1<R> visitor1);
}
public interface Visitor1<R> {
default R apply(Type t1) {
return t1.accept(this);
}
R visit(Type.Type1 t1);
R visit(Type.Type2 t1);
R visit(Type.Type3 t1);
}
public interface Visitor2<R> extends Visitor1<Visitor1<R>> {
default R apply(Type t1, Type t2) {
return apply(t1).apply(t2);
}
@Override
default Visitor1<R> visit(Type.Type1 t1) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t2) {
return Visitor2.this.visit(t1, t2);
}
@Override
public R visit(Type.Type2 t2) {
return Visitor2.this.visit(t1, t2);
}
@Override
public R visit(Type.Type3 t2) {
return Visitor2.this.visit(t1, t2);
}
};
}
@Override
default Visitor1<R> visit(Type.Type2 t1) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t2) {
return Visitor2.this.visit(t1, t2);
}
@Override
public R visit(Type.Type2 t2) {
return Visitor2.this.visit(t1, t2);
}
@Override
public R visit(Type.Type3 t2) {
return Visitor2.this.visit(t1, t2);
}
};
}
@Override
default Visitor1<R> visit(Type.Type3 t1) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t2) {
return Visitor2.this.visit(t1, t2);
}
@Override
public R visit(Type.Type2 t2) {
return Visitor2.this.visit(t1, t2);
}
@Override
public R visit(Type.Type3 t2) {
return Visitor2.this.visit(t1, t2);
}
};
}
R visit(Type.Type1 t1, Type.Type1 t2);
R visit(Type.Type1 t1, Type.Type2 t2);
R visit(Type.Type1 t1, Type.Type3 t2);
R visit(Type.Type2 t1, Type.Type1 t2);
R visit(Type.Type2 t1, Type.Type2 t2);
R visit(Type.Type2 t1, Type.Type3 t2);
R visit(Type.Type3 t1, Type.Type1 t2);
R visit(Type.Type3 t1, Type.Type2 t2);
R visit(Type.Type3 t1, Type.Type3 t2);
}
public interface CommutativeVisitor2<R> extends Visitor2<R> {
@Override
default R visit(Type.Type2 t1, Type.Type1 t2) {
return apply(t2, t1);
}
@Override
default R visit(Type.Type3 t1, Type.Type1 t2) {
return apply(t2, t1);
}
@Override
default R visit(Type.Type3 t1, Type.Type2 t2) {
return apply(t2, t1);
}
}
public interface Visitor3<R> extends Visitor2<Visitor1<R>> {
default R apply(Type t1, Type t2, Type t3) {
return apply(t1, t2).apply(t3);
}
@Override
default Visitor1<R> visit(Type.Type1 t1, Type.Type1 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type1 t1, Type.Type2 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type1 t1, Type.Type3 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type2 t1, Type.Type1 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type2 t1, Type.Type2 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type2 t1, Type.Type3 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type3 t1, Type.Type1 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type3 t1, Type.Type2 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
@Override
default Visitor1<R> visit(Type.Type3 t1, Type.Type3 t2) {
return new Visitor1<>() {
@Override
public R visit(Type.Type1 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type2 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
@Override
public R visit(Type.Type3 t3) {
return Visitor3.this.visit(t1, t2, t3);
}
};
}
R visit(Type.Type1 t1, Type.Type1 t2, Type.Type1 t3);
R visit(Type.Type1 t1, Type.Type1 t2, Type.Type2 t3);
R visit(Type.Type1 t1, Type.Type1 t2, Type.Type3 t3);
R visit(Type.Type1 t1, Type.Type2 t2, Type.Type1 t3);
R visit(Type.Type1 t1, Type.Type2 t2, Type.Type2 t3);
R visit(Type.Type1 t1, Type.Type2 t2, Type.Type3 t3);
R visit(Type.Type1 t1, Type.Type3 t2, Type.Type1 t3);
R visit(Type.Type1 t1, Type.Type3 t2, Type.Type2 t3);
R visit(Type.Type1 t1, Type.Type3 t2, Type.Type3 t3);
R visit(Type.Type2 t1, Type.Type1 t2, Type.Type1 t3);
R visit(Type.Type2 t1, Type.Type1 t2, Type.Type2 t3);
R visit(Type.Type2 t1, Type.Type1 t2, Type.Type3 t3);
R visit(Type.Type2 t1, Type.Type2 t2, Type.Type1 t3);
R visit(Type.Type2 t1, Type.Type2 t2, Type.Type2 t3);
R visit(Type.Type2 t1, Type.Type2 t2, Type.Type3 t3);
R visit(Type.Type2 t1, Type.Type3 t2, Type.Type1 t3);
R visit(Type.Type2 t1, Type.Type3 t2, Type.Type2 t3);
R visit(Type.Type2 t1, Type.Type3 t2, Type.Type3 t3);
R visit(Type.Type3 t1, Type.Type1 t2, Type.Type1 t3);
R visit(Type.Type3 t1, Type.Type1 t2, Type.Type2 t3);
R visit(Type.Type3 t1, Type.Type1 t2, Type.Type3 t3);
R visit(Type.Type3 t1, Type.Type2 t2, Type.Type1 t3);
R visit(Type.Type3 t1, Type.Type2 t2, Type.Type2 t3);
R visit(Type.Type3 t1, Type.Type2 t2, Type.Type3 t3);
R visit(Type.Type3 t1, Type.Type3 t2, Type.Type1 t3);
R visit(Type.Type3 t1, Type.Type3 t2, Type.Type2 t3);
R visit(Type.Type3 t1, Type.Type3 t2, Type.Type3 t3);
}
public static final class Cat implements Visitor2<String> {
public String visit(Type.Type1 t1, Type.Type1 t2) {
return "Type1-Type1";
}
public String visit(Type.Type1 t1, Type.Type2 t2) {
return "Type1-Type2";
}
public String visit(Type.Type1 t1, Type.Type3 t2) {
return "Type1-Type3";
}
public String visit(Type.Type2 t1, Type.Type1 t2) {
return "Type2-Type1";
}
public String visit(Type.Type2 t1, Type.Type2 t2) {
return "Type2-Type2";
}
public String visit(Type.Type2 t1, Type.Type3 t2) {
return "Type2-Type3";
}
public String visit(Type.Type3 t1, Type.Type1 t2) {
return "Type3-Type1";
}
public String visit(Type.Type3 t1, Type.Type2 t2) {
return "Type3-Type2";
}
public String visit(Type.Type3 t1, Type.Type3 t2) {
return "Type3-Type3";
}
}
public static final class Sum implements CommutativeVisitor2<Integer> {
@Override
public Integer visit(Type.Type1 t1, Type.Type1 t2) {
return 2;
}
@Override
public Integer visit(Type.Type1 t1, Type.Type2 t2) {
return 3;
}
@Override
public Integer visit(Type.Type1 t1, Type.Type3 t2) {
return 4;
}
@Override
public Integer visit(Type.Type2 t1, Type.Type2 t2) {
return 4;
}
@Override
public Integer visit(Type.Type2 t1, Type.Type3 t2) {
return 5;
}
@Override
public Integer visit(Type.Type3 t1, Type.Type3 t2) {
return 6;
}
}
public static final class ToString implements Visitor1<String> {
@Override
public String visit(Type.Type1 t1) {
return "Type1";
}
@Override
public String visit(Type.Type2 t1) {
return "Type2";
}
@Override
public String visit(Type.Type3 t1) {
return "Type3";
}
}
public static final class Cat3 implements Visitor3<String> {
@Override
public String visit(Type.Type1 t1, Type.Type1 t2, Type.Type1 t3) {
return "Type1-Type1-Type1";
}
@Override
public String visit(Type.Type1 t1, Type.Type1 t2, Type.Type2 t3) {
return "Type1-Type1-Type2";
}
@Override
public String visit(Type.Type1 t1, Type.Type1 t2, Type.Type3 t3) {
return "Type1-Type1-Type3";
}
@Override
public String visit(Type.Type1 t1, Type.Type2 t2, Type.Type1 t3) {
return "Type1-Type2-Type1";
}
@Override
public String visit(Type.Type1 t1, Type.Type2 t2, Type.Type2 t3) {
return "Type1-Type2-Type2";
}
@Override
public String visit(Type.Type1 t1, Type.Type2 t2, Type.Type3 t3) {
return "Type1-Type2-Type3";
}
@Override
public String visit(Type.Type1 t1, Type.Type3 t2, Type.Type1 t3) {
return "Type1-Type3-Type1";
}
@Override
public String visit(Type.Type1 t1, Type.Type3 t2, Type.Type2 t3) {
return "Type1-Type3-Type2";
}
@Override
public String visit(Type.Type1 t1, Type.Type3 t2, Type.Type3 t3) {
return "Type1-Type3-Type3";
}
@Override
public String visit(Type.Type2 t1, Type.Type1 t2, Type.Type1 t3) {
return "Type2-Type1-Type1";
}
@Override
public String visit(Type.Type2 t1, Type.Type1 t2, Type.Type2 t3) {
return "Type2-Type1-Type2";
}
@Override
public String visit(Type.Type2 t1, Type.Type1 t2, Type.Type3 t3) {
return "Type2-Type1-Type3";
}
@Override
public String visit(Type.Type2 t1, Type.Type2 t2, Type.Type1 t3) {
return "Type2-Type2-Type1";
}
@Override
public String visit(Type.Type2 t1, Type.Type2 t2, Type.Type2 t3) {
return "Type2-Type2-Type2";
}
@Override
public String visit(Type.Type2 t1, Type.Type2 t2, Type.Type3 t3) {
return "Type2-Type2-Type3";
}
@Override
public String visit(Type.Type2 t1, Type.Type3 t2, Type.Type1 t3) {
return "Type2-Type3-Type1";
}
@Override
public String visit(Type.Type2 t1, Type.Type3 t2, Type.Type2 t3) {
return "Type2-Type3-Type2";
}
@Override
public String visit(Type.Type2 t1, Type.Type3 t2, Type.Type3 t3) {
return "Type2-Type3-Type3";
}
@Override
public String visit(Type.Type3 t1, Type.Type1 t2, Type.Type1 t3) {
return "Type3-Type1-Type1";
}
@Override
public String visit(Type.Type3 t1, Type.Type1 t2, Type.Type2 t3) {
return "Type3-Type1-Type2";
}
@Override
public String visit(Type.Type3 t1, Type.Type1 t2, Type.Type3 t3) {
return "Type3-Type1-Type3";
}
@Override
public String visit(Type.Type3 t1, Type.Type2 t2, Type.Type1 t3) {
return "Type3-Type2-Type1";
}
@Override
public String visit(Type.Type3 t1, Type.Type2 t2, Type.Type2 t3) {
return "Type3-Type2-Type2";
}
@Override
public String visit(Type.Type3 t1, Type.Type2 t2, Type.Type3 t3) {
return "Type3-Type2-Type3";
}
@Override
public String visit(Type.Type3 t1, Type.Type3 t2, Type.Type1 t3) {
return "Type3-Type3-Type1";
}
@Override
public String visit(Type.Type3 t1, Type.Type3 t2, Type.Type2 t3) {
return "Type3-Type3-Type2";
}
@Override
public String visit(Type.Type3 t1, Type.Type3 t2, Type.Type3 t3) {
return "Type3-Type3-Type3";
}
}
public static void main(String[] args) {
Type unknownType1 = new Type.Type1();
Type unknownType2 = new Type.Type2();
Type unknownType3 = new Type.Type1();
var cat = new Cat();
System.out.println(cat.apply(unknownType1, unknownType2));
System.out.println(cat.apply(unknownType2, unknownType1));
var sum = new Sum();
System.out.println(sum.apply(unknownType1, unknownType2));
System.out.println(sum.apply(unknownType2,unknownType1));
var toString = new ToString();
System.out.println(toString.apply(unknownType1));
System.out.println(toString.apply(unknownType2));
var cat3 = new Cat3();
System.out.println(cat3.apply(unknownType1, unknownType2, unknownType3));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment