Есть ли что-то плохое в объявлении вложенного класса внутри интерфейса в 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 есть определение класса критериев внутри него, поэтому, когда вы блуждаете по коду, вы должны знать, в какой части файла вы находитесь.

Что еще более важно, разделение делает код объектов более простым и явным. Для меня это переопределяет все другие проблемы (ах, кроме кода, который, конечно, правильный). Я нахожу, что простота и экспликация полезны, когда речь идет о сохранении моих волос или, по крайней мере, о людях, которые будут поддерживать этот материал...