Является ли интерфейс сервисного слоя излишним?

Java задняя часть

Это 16-й день моего участия в августовском испытании обновлений.Подробности о событии:Испытание августовского обновления

Сегодня мы хотим обсудить следующий вопрос: нужен ли интерфейс сервисному слою?

Теперь давайте посмотрим на проекты, в которых я участвовал, и некоторые исходные коды проектов, которые я читал. Если «в проекте используется инфраструктура внедрения зависимостей, такая как Spring, нет необходимости использовать интерфейсы»!

Давайте поговорим о том, почему вы не можете использовать интерфейс после использования фреймворка внедрения зависимостей!

Причины отсутствия необходимости в интерфейсе

Я разобрал причины, по которым необходимо добавить интерфейсы для поддержки уровня службы и уровня Dao, и резюмировал их следующим образом:

  • Вы можете написать код верхнего уровня без реализации конкретной логики службы, такой как вызов службы контроллера.

  • По умолчанию Spring реализует АОП на основе динамических прокси, а для динамических прокси требуются интерфейсы.

  • Можно реализовать несколько реализаций Сервиса

На самом деле, ни одна из этих трех причин не работает!

Давайте поговорим о первой причине: «Верхний уровень может быть закодирован без реализации логики нижнего уровня»! Очень типичное интерфейсно-ориентированное программирование, развязка между слоями, кажется, проблем нет.

Этот метод разработки подходит для разных модулей, разработанных разными людьми или проектными группами, потому что стоимость коммуникации относительно велика. В то же время избегайте взаимного влияния из-за различий в ходе разработки между проектными командами.

Но давайте вспомним, в общей разработке проектов, сколько проектных команд делят задачи разработки по уровням? На самом деле, большинство проектов разделены по функциям. Даже в текущей ситуации, когда фронт и бэкенд разделены, чистая бэкенд разработка делится на задачи по функциональным модулям, то есть один человек отвечает за полную логическую обработку от уровня контроллера до уровня DAO. В этом случае каждый уровень сначала определяет интерфейс, а затем реализует логику, в дополнение к увеличению рабочей нагрузки разработчиков (конечно, если объем кода включен в рабочую нагрузку, то разработчики не должны слишком ограничиваться интерфейсами. !), что на самом деле бесполезно.

Если разработчик хочет разработать логику верхнего уровня до того, как будет завершена логика нижнего уровня, он может написать пустой метод класса нижнего уровня, чтобы сначала завершить логику верхнего уровня.

Вот рекомендуемый процесс разработки, который я предпочитаю, процесс кодирования сверху вниз:

  • Сначала напишите логику на уровне контроллера и напишите код вызова непосредственно, когда вы столкнетесь с местом, где вам нужно делегировать вызов службы. Приоритет для завершения процесса уровня контроллера

  • Затем используйте автодополнение IDE, чтобы сгенерировать соответствующие классы и методы для кода, который только что вызвал нижний уровень, и добавьте в него TODO.

  • После того, как все классы и методы будут завершены на основе TODO, следуйте описанному выше процессу, чтобы улучшать логику один за другим.

Этот метод может дать вам лучшее понимание бизнес-процесса.

По второй причине вообще не держится. Spring по умолчанию основан на динамическом прокси-сервере, но CGLib можно использовать для реализации АОП посредством настройки. CGLib не требует интерфейса.

Последняя причина — «несколько реализаций Сервиса». Эта причина недостаточна или не учитывает место происшествия. Фактически, в большинстве случаев множественная реализация не требуется, или можно использовать другие методы для замены множественной реализации на основе интерфейса.

Кроме того, для многих проектов, использующих интерфейсы, структура проекта также вызывает вопросы! Ниже мы объединяем структуру проекта для иллюстрации.

Структура проекта и реализация интерфейса

Общая структура проекта разделена на слои следующим образом:

  • Controller

  • Service

  • Dao

В случаях, когда не требуется несколько реализаций, нет необходимости в интерфейсе. Приведенной выше структуры проекта достаточно.

Для ситуаций, требующих нескольких реализаций, либо сейчас, либо позже. В этом случае, похоже, требуется интерфейс. Структура проекта на данный момент выглядит так:

  • Controller

  • Service

    • ---- интерфейс в упаковке

    • impl --- реализовано в другом пакете

  • Dao

Что нам следует делать для приведенной выше структуры, когда мы рассматриваем несколько реализаций?

Первый способ — добавить в Сервис новый пакет, прописать в нем новую логику, а затем изменить файл конфигурации, чтобы использовать новую реализацию в качестве объекта внедрения.

  • Controller

  • Service

    • ---- интерфейс в упаковке

    • impl --- реализовано в другом пакете

    • impl2 --- новая реализация в другом пакете

  • Dao

Второй способ — добавить модуль Service и написать в нем новую логику (учтите, что пакет здесь не может быть таким же, как исходный пакет Service, либо пакет тот же, но имя класса другое, иначе класс не может быть Создан. Потому что он должен быть загружен при загрузке. Загрузите два модуля службы одновременно. Если имя пакета и имя класса совпадают, полное имя класса двух модулей будет одинаковым!), а затем измените конфигурацию. файл для использования новой логики в качестве объекта внедрения.

  • Controller

  • Service

    • ---- интерфейс в упаковке

    • impl --- реализовано в другом пакете

  • Service2

    • impl2 --- новая реализация в другом пакете
  • Dao

Условно говоря, фактический первый метод относительно прост, и ему нужно сосредоточиться только на уровне пакета. Второй способ должен сосредоточиться на уровнях модуля и пакета. Кроме того, оба эти метода фактически приводят к включению в проект ненужного логического кода. Потому что старая логика будет упакована в мешок.

Однако со структурной точки зрения структура собственно режима 2 более ясна, чем структура режима 1, поскольку логику можно отличить от модуля.

Есть ли способ объединить преимущества обоих? Ответ - да, и это не сложно!

Сначала разделите интерфейс и реализацию как отдельный модуль:

  • Controller

  • Сервис --- Интерфейсный модуль

  • ServiceImpl

    • impl --- реализовано в другом пакете
  • ServiceImpl2

    • impl2 --- новая реализация в другом пакете
  • Dao

Во-вторых, настройте конфигурацию упаковки, выберите между ServiceImpl и ServiceImpl2. Поскольку ServiceImpl и ServiceImpl2 являются альтернативами, структуры пакетов ServiceImpl и ServiceImpl2 могут быть одинаковыми. Структура пакета та же, после настройки зависимостей конфигурацию, связанную с внедрением зависимостей, не нужно настраивать. После настройки структура проекта выглядит так:

  • Controller

  • Сервис --- Интерфейсный модуль

  • ServiceImpl

    • impl --- реализовано в другом пакете
  • ServiceImpl2

    • impl --- новая реализация и старая реализация в одном пакете
  • Dao

Теперь структура пакета и имена классов в модулях ServiceImpl и ServiceImpl2 одинаковы. Так нужны ли нам интерфейсные модули?

Предположим, мы удалим модуль интерфейса Service, и структура станет следующей:

  • Controller

  • Service1 --- старая реализация

  • Service2 --- новая реализация

  • Dao

Можно ли добиться нескольких реализаций Сервисов, просто настроив зависимости модулей? Ответ очевиден, верно?

Недостатки неиспользования интерфейсов

Причины неиспользования интерфейсов приведены выше. Однако неиспользование интерфейсов не лишено недостатков: основная проблема заключается в отсутствии строгой спецификации интерфейса при реализации нескольких реализаций. То есть быстро сгенерировать код фреймворка с помощью IDE, реализовав интерфейс, невозможно. Для нереализованных интерфейсов IDE также может выдавать напоминания об ошибках.

Менее элегантное решение — скопировать код из исходного модуля в новый модуль и реализовать новую логику на основе старого кода.

Поэтому, если проекту требуется несколько реализаций и большое количество множественных реализаций (но обычно проекты не будут иметь множественных реализаций), рекомендуется использовать интерфейсы. В противном случае нет необходимости использовать интерфейс.

Суммировать

В этой статье рассматривается вопрос «нужен ли интерфейс сервисному уровню» и указывается причина необходимости интерфейса. И мои личные взгляды на этот вопрос, надеюсь, будут вам чем-то полезны.