У меня есть класс обслуживания, который содержит несколько методов, как показано ниже. Специфика того, что делает этот класс, описана в конце этого сообщения.
public class Service{
public Foo m_a( /* args_a */ ){ ... }
public Bar m_b( /* args_b */ ){ ... }
// and so on
}
Все общедоступные методы в этой службе имеют одну общую черту: они вызывают метод init()
прежде чем делать что-либо еще. Итак, моя услуга выглядит примерно так:
public class Service{
private int attr;
private void init(int val){
this.attr = val;
}
public Foo m_a(int val_a, ...){
init(val_a);
// time for business A
}
public Bar m_b(int val_b, ...){
init(val_b);
// time for business B
}
// and so on
}
Поскольку другие методы могут быть добавлены в Service
в будущем, я думаю, что дизайн выше довольно беден. Парень, который реализует новый метод для этого класса, может сначала не следовать правилу вызова init(val_x)
, и это может привести к ошибкам.
Чтобы гарантировать, что init()
всегда вызывается, я могу создать некоторый прокси-метод, который выполняет работу систематически:
public class Service{
// Init method
private int attr;
private void init(int val){
this.attr = val;
}
/*
* The only public method in the service is a proxy,
* that always calls init() before calling the actual requested method
*/
public Object invoke(String method, int val, Map<String,Object> args){
init(val);
switch(method){
case "m_a":
return m_a(args.get("name"),...);
case "m_b":
return m_b(args.get("myArg"),...);
default: // launch some exception
}
}
private Foo m_a( /* args_a */ ){ ... }
private Bar m_b( /* args_b */ ){ ... }
// and so on
}
Я думаю, что это намного лучший подход, и разработчик, который должен поддерживать код, не составит труда понять, что происходит.
Однако я вижу большой недостаток в этом решении: удобство использования для пользователя!
Map
перед вызовом метода invoke
, вместо того, чтобы вводить аргументы непосредственно в подписи методаinvoke
является Object
, который чрезвычайно неоднозначен и требует от пользователя применения кастинга при каждом вызове invoke
У вас, ребята, какая-нибудь умная идея о том, как удалить эти проблемы, и все еще держите эту идею прокси?
Service
Фактически я занимаюсь внедрением REST API. Целью этого API является доступ к конкретным ресурсам, хранящимся в базе данных. Например:
GET http://fortheking.com/topic/3
Эти HTTP-запросы будут связаны с методом службы, который извлекает конкретную тему, учитывая ее идентификатор.
На практике "тема" - это имя ресурса, к которому необходимо получить доступ. Это точка входа для каждого метода моего класса Service
, и поэтому существует некоторый общий код для применения до фактического запуска предполагаемой логики метода. Я поставил такой код в init()
.
По сути, вы хотите использовать Java-прокси с помощью ApplicationHandler. Этот блог немного устарел, но объясняет основные понятия: http://www.ibm.com/developerworks/library/j-jtp08305/ - раздел "Динамические прокси-серверы", возможно, наиболее важен для вас. Идея заключается в том, что вы вернете экземпляр "Service" для ваших вызывающих абонентов, который действительно является прокси-объектом. В этом прокси InvocationHandler вы можете вызвать метод init(), а затем выполнить основной метод. Если у вас есть существующие методы, которые также вызывают init(), вам нужно либо убедиться, что init() является idempotent, либо изменить код, чтобы не вызывать его дважды.
Одно из ограничений этого подхода заключается в том, что вы можете создавать прокси для интерфейса, а не для класса. (Если это ограничение не было отменено в какой-то новой версии Java, на которую я еще не смотрел.) Я признаю, что ваш примерный код выше упрощен, но вы не показываете никаких интерфейсов, так что это может быть что-то, что вам нужно представить первый. Самое главное, что вызывающие абоненты вашей службы должны напрямую использовать интерфейс, а не класс сервиса.
init
? Лично мне вообще не нравится этот дизайн прокси. Я предполагаю, что в дизайне вашего класса есть еще одна «проблема», которая вызывает необходимостьinit
в ваших сообщениях.