Во-первых, в пункте 2 я не понимаю:
мой Composite Aggregate должен реализовать 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
вызовет проблемы в бизнесе, и я не могу гарантировать, что он не будет выброшен с помощью надлежащего тестирования (кроме того, я нашел это очень увлекательным).
person
rascio
schedule
20.09.2019