Во-первых, в пункте 2 я не получаю:
мой составной агрегат должен реализовать Visitor
Первый вопрос, который приходит мне в голову: почему?Разве вы не можете объявить посетителя как интерфейс и передать реализацию как входной параметр вашего агрегата?
Есть ли способ имитировать динамическое связывание в java для перегруженных методов (кроме instanceof -так как это решило бы мою проблему с вариантом 1)?
Да, вы можете сделать это с помощью Reflections, но реальный вопрос заключается в том, хотите ли вы их использовать?
Я думаю, что ответ зависит от того, сколько случаев вы должны решатьи как часто они меняются?
Если у вас есть «управляемое» количество различных случаев, решение с instanceof
может быть хорошей сделкой:
public Something myMethod(Entity entity){
if (entity instanceof AnEntity){
//do stuffs
else if (entity instanceof AnotherEntity){
//do something else
...
else {
throw new RuntimeException("Not managed " + entity.getClass().getName());
}
}
В противном случае, когда, возможно, выЕсли у вас больше дел и вы хотите разделить код на свои собственные методы, вы можете сделать это с помощью Java MethodHandle
, позвольте мне опубликовать пример использования:
package virtualmethods;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MyObject {
public String doStuffs(Object i) throws Throwable {
try {
final MethodType type = MethodType.methodType(String.class, i.getClass());
return (String) MethodHandles.lookup()
.findVirtual(getClass(), "doStuffs", type)
.invoke(this, i);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Not managed " + i.getClass().getName(), e);
}
}
private String doStuffs(Integer i) {
return "You choose " + i;
}
private String doStuffs(Boolean b) {
return "You choose boolean " + b;
}
}
, а затем использовать его:
package virtualmethods;
public class Main {
public static void main(String[] args) throws Throwable {
MyObject object = new MyObject();
System.out.println("Integer => " + object.doStuffs(5));
System.out.println("Boolean => " + object.doStuffs(true));
try {
System.out.println("String => " + object.doStuffs("something"));
}
catch (Throwable e) {
System.out.println("KABOOM");
e.printStackTrace();
}
}
}
Метод public в MyObject
, принимающий Object
, будет искать метод с именем doStuffs
с результатом String
и i.getClass()
в качестве входных данных в классе MyObject
(дополнительная информация здесь ).
Используя этот способ, вы можете отправлять методы во время выполнения (использование перегрузки - статическое связывание во время компиляции).Но оба метода имеют проблему, состоящую в том, что вы не можете быть уверены, что будете управлять ВСЕМИ типами, которые расширяют / реализуют Entity
в первом случае и / или Object
во втором, оба решения имеют else
илиcatch
чтобы проверить, когда в метод передается неуправляемый тип.
Будьте на 100% уверены, что вы управляете всеми типами, может быть достигнуто только с помощью решения, предложенного @ jaco0646, поскольку, насколько я знаю, оно заставляет васуправлять всеми типами, иначе он не скомпилируется.Учитывая необходимое количество шаблонов, которые я бы использовал, я бы использовал только при броске, что RuntimeException
вызовет бизнес-проблему, и я не могу гарантировать, что его не выбрасывают с помощью надлежащего тестирования (помимо этого я нашел это очень увлекательным).