У меня есть интерфейс ProductService
с методом findByCriteria
. Этот метод имел длинный список nullable параметров, как productName
, maxCost
, minCost
, producer
и так далее.
Я осуществил рефакторинг этот метод путем представления Объекта параметра. Я создал класс SearchCriteria
и теперь сигнатура метода похожа на это:
findByCriteria (SearchCriteria criteria)
Я думал это экземпляры SearchCriteria
только создаются вызывающими сторонами метода и только используются внутри findByCriteria
метод, т.е.:
void processRequest() {
SearchCriteria criteria = new SearchCriteria ()
.withMaxCost (maxCost)
.......
.withProducer (producer);
List products = productService.findByCriteria (criteria);
....
}
и
List findByCriteria(SearchCriteria criteria) {
return doSmthAndReturnResult(criteria.getMaxCost(), criteria.getProducer());
}
Таким образом, я не хотел создавать отдельный общедоступный класс для SearchCriteria
и вставленный это ProductServiceInterface
:
public interface ProductService {
List findByCriteria (SearchCriteria criteria);
static class SearchCriteria {
...
}
}
Есть ли что-нибудь плохо с этим интерфейсом? Куда Вы поместили бы SearchCriteria
класс?
Я думаю, это неплохо выглядит. Это ясно указывает на то, что SearchCriteria
предназначен для использования с ProductService
s.
Некоторые люди, однако, возразят, что вложенные классы выглядят немного странно, и утверждают, что это было бы чрезмерным дизайном и что в большинстве случаев, включая этот, достаточно хорошей области видимости пакета.
Я бы посоветовал вам использовать классы, когда у вас есть методы, которые могут требовать более или менее обнуляемых аргументов; он дает вам возможность предоставить все, что вам нужно, без необходимости вызывать такой метод, как:
someMethod("foo", null, null, null, null, null, null, ..., "bar");
Используя такой механизм, вызов метода будет примерно таким:
someMethod(new ObjParam().setFoo("foo").setBar("bar"));
Второй метод является одноразовым и многоразовым (без множества переопределений методов ). И я не говорю здесь, что переопределение метода - это плохо! Наоборот. Однако со многими необязательными аргументами я бы предпочел второй вызов.
Что касается внутренних классов, они иногда полезны, но я лично следую этим рекомендациям:
Имейте в виду, что, внутренний класс или нет, компилятор Java будет создать .class для каждого класса. Чем больше вы их используете, тем менее читабельным будет ваш код. В значительной степени вам решать, оправданы они или нет ...
Это неплохо и может быть полезно, если вы хотите более плотную группировку между интерфейсами и некоторыми вспомогательными объектами, такими как компараторы. (Я сделал то же самое с интерфейсом и внутренними классами, предоставляющими полезные компараторы, которые сравнивают экземпляры интерфейса.)
это может быть немного неудобно для клиентов, поскольку они должны префикс имени внутреннего класса с помощью имя интерфейса (или используйте статический импорт), но хорошая IDE позаботится об этом за вас (но код может быть приправлен объявлениями Interface.SomeClass
, что выглядит не очень хорошо.)
Однако в конкретном случае SearchCriteria
выглядит не столь тесно связанным с интерфейсом, поэтому его можно использовать как обычный класс пакета.
Боюсь, я хочу проголосовать за плохое. В любом случае, довольно плохо, можно делать и похуже ...
Для простоты класс должен стремиться только к одной ответственности. В вашей реализации ProductService есть определение класса критериев, поэтому, когда вы бродите по коду, вы должны знать, в какой части файла вы находитесь.
Что еще более важно, разделение делает код задействованных сущностей проще и эффективнее. явный. Для меня это перекрывает все другие проблемы (ах, кроме правильного кода, конечно). Я считаю, что простота и ясность наиболее полезны, когда дело касается сохранения моих волос или, по крайней мере, тех, кто будет ухаживать за ними ...