Я работаю над крошечной веб-библиотекой и задаюсь вопросом, нужно ли мне вызывать методы обработчика HTTP для GET, POST, PUT и т. Д. Рефлекторно или нет.
Фиксированные методы
Сначалавариант с if else ...
блочными вызывающими методами, данными в базовом классе, где у них есть реализация по умолчанию, возвращающая ошибку клиенту.Поскольку для запроса к неподдерживаемому методу требуется заголовок с разрешенными методами, мне нужно подумать о том, какие методы в действительности переопределяются (как, впрочем, и API Servlet).
public abstract class Resource {
public Response handle(HttpServletRequest request) {
String action = request.getMethod();
if(action.equals("GET"))
return get(request);
else if(action.equals("POST"))
return post(request);
...
}
protected Response get(HttpServletRequest request) {
return new Response(METHOD_NOT_ALLOWED);
}
protected Response post(HttpServletRequest request) {
return new Response(METHOD_NOT_ALLOWED);
}
}
Недостатком этого решения является уменьшенная гибкость, поскольку используемые методы фиксируются в базовом классе до тех пор, пока методы handle
не будут переопределены в подклассе.
Переменные методы
Другой вариант заключается в рефлексивном поиске методов-обработчиков HTTP в зависимости от их сигнатуры (возьмите HttpServletRequest
и верните Response
).Эти методы будут храниться в Map и вызываться рефлексивно в зависимости от ключа на карте.
public abstract class Resource {
private Map<String, Method> handlers;
public Resource() {
handlers = findHttpHandlerMethodsReflectivly();
}
public Response handle(HttpServletRequest request) {
String action = request.getMethod();
Method handler = handlers.get(action);
return (Response)handler.invoke(this, request);
}
}
Преимущество этого решения заключается в простой реализации и гибкости, но недостатки, возможно, немного больше времени выполненияиз-за поиска на карте и вызова рефлексивного метода.И интерфейс класса несколько «мягкий» (или динамический), и у компилятора нет шансов проверить это.Но я не уверен, что это будет недостатком, поскольку никакие другие классы не должны полагаться на методы-обработчики HTTP, они являются внешним веб-интерфейсом и границей системы Java.
Шаблон стратегии
Третий вариант и самый чистый ООП - это модель стратегии, рекомендованная «полигеномасляными материалами».Это будет выглядеть так:
class MyResource extends Resource {
register("GET",
new RequestHandler{
@Override Response handle(HttpServletRequest request) {
new Response(OK);
}
}
);
}
Это чистый ООП, но код действительно уродливый и многословный.Я бы предпочел Scala с замыканиями здесь, хотя инструментальная поддержка Scala все еще слабая.Сравните это с решением с наследованием и фиксированными методами:
class MyResource extends Resource {
@Override Response get(HttpServletRequest request) {
return new Resonse(OK);
}
}
Что бы вы предпочли и почему?Другие идеи?
Решение
Я узнал, что рефлексия здесь не нужна из-за фиксированного набора методов HTTP.Подход с шаблоном стратегии является чистым, но он кажется мне многословным.Поэтому я решил пойти с фиксированными методами и наследованием.