Created
November 7, 2020 09:19
-
-
Save RayStarkMC/b14e9139ccde8bd025d22fd21a64b9bf to your computer and use it in GitHub Desktop.
Visitorパターンの2変数以上への拡張
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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