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