этот вопрос задавался много раз, но я не мог найти для него обходного пути. Этот пример работает по желанию:
public class RequestWrapper<T> {
private final T request;
private final Class<T> type;
public RequestWrapper(T request, Class<T> type) {
this.request = request;
this.type = type;
}
public T getRequest() {
return request;
}
public Class<T> getType() {
return type;
}
}
public class Service {
private void invoke(String request) {
System.out.println("String:" + request);
}
private void invoke(Object request) {
System.out.println("Object:" + request + "," + request.getClass().getSimpleName());
}
public static void main(String[] args) {
RequestWrapper<String> sw = new RequestWrapper<String>("A", String.class);
RequestWrapper<Integer> iw = new RequestWrapper<Integer>(Integer.valueOf(0), Integer.class);
new Service().invoke(sw.getRequest());
new Service().invoke(iw.getRequest());
}
}
Но мне нужно добавить еще один метод в класс Service, который делает что-то до/после вызова метода invoke:
public void invoke(RequestWrapper<?> wrapper) {
try {
// ...
invoke(wrapper.getType().cast(wrapper.getRequest()));
invoke(wrapper.getRequest());
} catch(Exception e ) {
// ...
}
}
то основной метод будет содержать:
new Service().invoke(sw);
Я понимаю причину, почему invoke (Object request) используется вместо invoke (запрос String). Что было бы элегантным решением для вызова надлежащего метода вызова и выполнения некоторых общих действий до/после него?
Чтобы иметь интерфейс, например Invoker, реализуйте его, например StringInvoker, Invoker> и вызывайте map.get(wrapper.getType()). Invoke (wrapper.getRequest()) - это возможное решение, но я ожидаю чего-то лучшего.
Посетитель может помочь решить эту проблему. Единственным недостатком является то, что писать невозможно:
new Service().invoke(new RequestWrapper<String>("A"));
Моя реализация:
public class Service {
public void invoke(RequestWrapper<?> wrapper) {
try {
// ...
wrapper.invoke(this);
} catch(Exception e ) {
// ...
}
}
public void invoke(String request) {
System.out.println("String:" + request);
}
public void invoke(Boolean request) {
System.out.println("Boolean:" + request);
}
public static void main(String[] args) {
RequestWrapper<Boolean> rw = new BooleanRequestWrapper(Boolean.TRUE);
new Service().invoke(rw);
}
}
abstract class RequestWrapper<T> {
protected final T request;
public RequestWrapper(T request) {
this.request = request;
}
public abstract void invoke(Service v);
}
class BooleanRequestWrapper extends RequestWrapper<Boolean> {
public BooleanRequestWrapper(Boolean request) {
super(request);
}
public void invoke(Service service) {
service.invoke(request);
}
}
Вы можете проверить тип и явно бросить его, например (я также добавил Integer
чтобы вы могли видеть разветвление на большее количество типов):
Class<?> c = wrapper.getType();
if (c == String.class)
invoke((String) wrapper.getRequest()); // Invokes invoke(String)
else if (c == Integer.class)
invoke((Integer) wrapper.getRequest()); // Invokes invoke(Integer)
else
invoke(wrapper.getRequest()); // Invokes invoke(Object)
Заметка:
Если вы продолжаете этот путь, вам даже не нужно сохранять тип запроса в классе RequestWrapper
потому что вы можете так же легко использовать оператор instanceof
на самом запросе, чтобы проверить его тип. И если вы "избавитесь" от типа запроса, ваш текущий класс RequestWrapper
будет содержать только запрос, поэтому RequestWrapper
даже не понадобится в этом случае.