Skip to content

Instantly share code, notes, and snippets.

@alexradzin alexradzin/Book.java
Created Feb 12, 2019

Embed
What would you like to do?
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

This comment has been minimized.

Copy link
Owner Author

commented Feb 12, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.