Skip to content

Instantly share code, notes, and snippets.

@alexradzin
Created February 12, 2019 00:21
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexradzin/4082d5957a49747134bdab3d5ed94907 to your computer and use it in GitHub Desktop.
Save alexradzin/4082d5957a49747134bdab3d5ed94907 to your computer and use it in GitHub Desktop.
Improved Visitor
package visitor;
public class Book implements Visitable {
private final String title;
private final int pageCount;
public Book(String title, int pageCount) {
this.title = title;
this.pageCount = pageCount;
}
public String getTitle() {
return title;
}
public int getPageCount() {
return pageCount;
}
}
package visitor;
public class Magazine implements Visitable {
private final String name;
private final int pageCountInVolume;
private final int volumes;
public Magazine(String name, int pageCountInVolume, int volumes) {
this.name = name;
this.pageCountInVolume = pageCountInVolume;
this.volumes = volumes;
}
public String getName() {
return name;
}
public int getPageCountInVolume() {
return pageCountInVolume;
}
public int getVolumes() {
return volumes;
}
}
package visitor;
import java.util.HashMap;
import java.util.Map;
public class Main {
private static void mapVisitorUsingConstructor() {
Book someBook = new Book("The Title", 200);
Magazine someMagazine = new Magazine("The name", 50, 12);
Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, Void>> printers = new HashMap<>();
printers.put(Book.class, (MonoVisitor<Book, Void>) book -> {
System.out.println(book.getTitle());
return null;
});
printers.put(Magazine.class, (MonoVisitor<Magazine, Void>) magazine -> {
System.out.println("magazine");
return null;
});
MapVisitor<Void> printVisitor = new MapVisitor<>(printers);
someBook.accept(printVisitor);
someMagazine.accept(printVisitor);
Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, Integer>> pagesRetriever = new HashMap<>();
pagesRetriever.put(Book.class, (MonoVisitor<Book, Integer>) Book::getPageCount);
pagesRetriever.put(Magazine.class, (MonoVisitor<Magazine, Integer>) magazine -> magazine.getPageCountInVolume() * magazine.getVolumes());
MapVisitor<Integer> pageCountVisitor = new MapVisitor<>(pagesRetriever);
System.out.println(someBook.accept(pageCountVisitor));
System.out.println(someMagazine.accept(pageCountVisitor));
}
private static void mapVisitorUsingBuilder() {
Book someBook = new Book("The Title", 200);
Magazine someMagazine = new Magazine("The name", 50, 12);
Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, Void>> printers = new HashMap<>();
printers.put(Book.class, (MonoVisitor<Book, Void>) book -> {
System.out.println(book.getTitle());
return null;
});
printers.put(Magazine.class, (MonoVisitor<Magazine, Void>) magazine -> {
System.out.println("magazine");
return null;
});
MapVisitor<Void> printVisitor = MapVisitor.builder(Void.class)
.with(Book.class, book -> {System.out.println(book.getTitle()); return null;})
.with(Magazine.class, magazine -> {System.out.println(magazine.getName()); return null;})
.build();
someBook.accept(printVisitor);
someMagazine.accept(printVisitor);
Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, Integer>> pagesRetriever = new HashMap<>();
pagesRetriever.put(Book.class, (MonoVisitor<Book, Integer>) Book::getPageCount);
pagesRetriever.put(Magazine.class, (MonoVisitor<Magazine, Integer>) magazine -> magazine.getPageCountInVolume() * magazine.getVolumes());
MapVisitor<Integer> pageCountVisitor = new MapVisitor<>(pagesRetriever);
System.out.println(someBook.accept(pageCountVisitor));
System.out.println(someMagazine.accept(pageCountVisitor));
}
public static void main(String[] args) {
mapVisitorUsingConstructor();
mapVisitorUsingBuilder();
}
}
package visitor;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
public class MapVisitor<R> implements Function<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>>, Predicate<Class<? extends Visitable>> {
private final Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> visitors;
public MapVisitor(Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> visitors) {
this.visitors = visitors;
}
@Override
public MonoVisitor<? extends Visitable, R> apply(Class<? extends Visitable> clazz) {
return visitors.get(clazz);
}
public static <R> Builder<R> builder(Class<R> returnType) {
return new Builder<>(returnType);
}
@Override
public boolean test(Class<? extends Visitable> clazz) {
return visitors.containsKey(clazz);
}
public static class Builder<R> {
private final Class<R> returnType;
private final Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> visitors = new HashMap<>();
private Builder(Class<R> returnType) {
this.returnType = returnType;
}
public <V extends Visitable> Builder<R> with(Class<V> clazz, MonoVisitor<V, R> visitor) {
visitors.put(clazz, visitor);
return this;
}
public MapVisitor<R> build() {
return new MapVisitor<>(visitors);
}
}
}
package visitor;
public interface MonoVisitor<T, R> {
R visit(T t);
}
package visitor;
import java.util.function.Function;
public interface Visitable <V extends Visitable> {
@SuppressWarnings("unchecked")
default <R> R accept(Function<Class<V>, MonoVisitor<V, R>> visitor) {
return visitor.apply((Class<V>)getClass()).visit((V)this);
}
}
@alexradzin
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment