Last active
July 1, 2022 19:10
-
-
Save stefanofago73/b92a99e2101f6e6e8f6f92441cba43ea to your computer and use it in GitHub Desktop.
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
import java.util.HashMap; | |
import java.util.function.Function; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
import java.util.stream.IntStream; | |
import java.util.Random; | |
interface Visitable<R,T extends Visitable<R,?>> { | |
default R accept(Visitor<R,T> visitor) | |
{ | |
return visitor.visit(cast(this)); | |
} | |
private T cast(Visitable<R, T> subject) | |
{ | |
@SuppressWarnings("unchecked") | |
T t = (T)this; | |
return t; | |
} | |
} | |
interface Visitor<R,T extends Visitable<R,?>> { | |
R visit(T elem); | |
static VisitorConf conf() | |
{ | |
HashMap<Class<?>, Visitor<?, ?>> lookup = new HashMap<>(); | |
return new VisitorConf() { | |
@Override | |
public <R, T extends Visitable<R, ?>> VisitorConf define(Class<T> clazz, Function<T, R> operation) { | |
lookup.put(clazz, (Visitor<R,T>)t->operation.apply(t)); | |
return this; | |
} | |
public <R,T extends Visitable<R,?>> R explore(T subject) | |
{ | |
@SuppressWarnings("unchecked") | |
Visitor<R,T> visitor = ((Visitor<R,T>)lookup.get(subject.getClass())); | |
return visitor.visit(subject); | |
} | |
private Visitor<?, Visitable<?, ?>> toVisitor(List<Visitor<?,?>> visitors, int idx) | |
{ | |
@SuppressWarnings("unchecked") | |
var visitor = ((Visitor<?, Visitable<?, ?>>)visitors.get(idx)); | |
return visitor; | |
} | |
public <T extends Visitable<?,?>> List<?> explore(List<T> subjects) | |
{ | |
List<Visitor<?,?>> visitors = subjects.stream() | |
.map(Object::getClass) | |
.map(lookup::get) | |
.collect(Collectors.toList()); | |
return IntStream | |
.range(0, subjects.size()) | |
.mapToObj(idx -> toVisitor(visitors, idx).visit(subjects.get(idx))) | |
.collect(Collectors.toList()); | |
} | |
}; | |
} | |
interface VisitorConf | |
{ | |
<R,T extends Visitable<R,?>> VisitorConf define(Class<T> clazz, Function<T,R> operation); | |
<R,T extends Visitable<R,?>> R explore(T subject); | |
<T extends Visitable<?,?>> List<?> explore(List<T> subjects); | |
} | |
} | |
record Sub(int a,int b) implements Visitable<Integer, Sub> { | |
public int sub() | |
{ | |
return a-b; | |
} | |
} | |
record Sum(int a,int b) implements Visitable<Integer, Sum>{ | |
public int sum() | |
{ | |
return a+b; | |
} | |
} | |
record RndString() implements Visitable<String, RndString> { | |
public String produce() | |
{ | |
return Integer.toHexString(new Random().nextInt()); | |
} | |
} | |
public class Main { | |
public static void main(String args[]) { | |
var conf = Visitor.conf() | |
.<Integer, Sum>define(Sum.class, s -> s.sum()) | |
.<Integer, Sub>define(Sub.class, s -> s.sub()) | |
.<String,RndString>define(RndString.class,r->r.produce()); | |
System.out.println(conf.explore(Arrays.asList(new Sum(1,2),new Sum(3,4)))); | |
System.out.println(conf.explore(Arrays.asList(new Sum(1,2),new Sub(4,3), new RndString()))); | |
List<Visitable<?, ?>> list= Arrays.asList(new Sum(1,2),new Sub(4,3), new RndString()); | |
list.stream() | |
.map(conf::explore) | |
.collect(Collectors.toList()) | |
.forEach(System.out::println); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment