Skip to content

Instantly share code, notes, and snippets.

@stefanofago73
Last active July 1, 2022 19:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefanofago73/b92a99e2101f6e6e8f6f92441cba43ea to your computer and use it in GitHub Desktop.
Save stefanofago73/b92a99e2101f6e6e8f6f92441cba43ea to your computer and use it in GitHub Desktop.
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