Почему всегда существуют единые интерфейсы реализации в сервисе и дао?

Я работал/видел несколько проектов веб-приложений spring -hibernate, имеющих столько интерфейсов, что есть фактические классы обслуживания и дао.

Я всегда думал, что эти два являются основными причинами наличия этих единых интерфейсов реализации:

  • Spring может связать фактическую реализацию в качестве зависимостей в данном классе (свободная связь)

    public class Person { 
        @Autowired 
        private Address address;
    
        @Autowired 
        private AccountDetail accountDetail;
    
        public Person(Address address, AccountDetail accountDetail) 
        { // constructor
    
  • Во время модульного тестирования я могу создавать классы-макеты и тестировать класс в изоляции.

    Address mockedAddress = mock(Address);
    AccountDetail mockedAccountDetail = mock(AccountDetail);
    Person underTestPerson = new Person(mockedAddress, mockedAccountDetail); 
    // unit test follows
    

Но в последнее время я понял, что:

Spring может использовать конкретные классы реализации в качестве зависимостей:

public class Person { 

@Autowired 
private AddressImpl address;

@Autowired 
private AccountDetailImpl accountDetail;

public Person(AddressImpl address, AccountDetailImpl accountDetail) { 
// constructor

Макетные фреймворки, такие как EasyMock, могут также издеваться над конкретными классами

AddressImpl mockedAddress = mock(AddressImpl);
AccountDetailImpl mockedAccountDetail = mock(AccountDetailImpl);
Person underTestPerson = new Person(mockedAddress, mockedAccountDetail); 
// unit test follows

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

Итак, мой вопрос, почему мы все еще нуждаемся в интерфейсах, а затем имеем единые реализации, такие как * ServiceImpl и * DaoImpl классы и излишне увеличиваем размер базы кода. Есть ли какая-то проблема в насмешливых конкретных классах, о которых я не знаю.

Всякий раз, когда я обсуждал это с моими товарищами по команде, только ответ, который я получаю, заключается в том, что внедрение сервисов и классов dao на основе интерфейсов - это DESIGN, которые следуют за ними - они упоминают о spring лучших практиках, ООП, DDD и т.д. Но Я все еще не понимаю прагматичную причину наличия в интерфейсе столь большого количества интерфейсов.

Ответ 1

Есть больше преимуществ для интерфейсов - как и для проксирования. Если ваш класс реализует интерфейс, динамические прокси JDK будут использоваться по умолчанию для АОП. Если вы используете реализации напрямую, вы будете вынуждены использовать прокси CGLIB, создав proxy-target-class= true. Они требуют манипуляции с байтовым кодом, в отличие от прокси-серверов JDK.

прочитайте здесь, чтобы узнать больше об этом.

Прочитайте еще одно обсуждение в какие причины могут использоваться для использования интерфейсов (Java EE или Spring и JPA) для получения дополнительной информации.

Ответ 2

Это очень спорный вопрос. Короче говоря, там нет - по крайней мере, для вас, разработчика.

В мире EJB2 интерфейсы Home и Remote были обязательными и были именно по какой-то причине @AravindA упоминает: прокси. Безопасность, удаленный доступ, объединение в пул и т.д. Все могут быть завернуты в прокси-сервер и предоставлять услуги, запрашиваемые строго в стандартной библиотеке (как в DynamicProxy).

Теперь, когда у нас есть javaassist и cglib, Spring (Hibernate, EJB3, если вы предпочитаете), отлично справляются с вашими классами, как нравится разработчикам рамок. Проблема в том, что они делают очень неприятно: они обычно просят вас добавить конструктор без параметров. - Подождите, у меня были параметры здесь? -Невероятно, просто добавьте конструктор.

Таким образом, интерфейсы предназначены для поддержания вашего здравомыслия. Тем не менее, это странно, конструктор без аргументов для класса с соответствующим конструктором не является чем-то, что имеет смысл для меня, не так ли? Оказывается (я должен был прочитать спецификацию, я знаю), что Spring создает функциональный эквивалент интерфейса из вашего класса: экземпляр без состояния (или игнорируется) и все переопределенные методы. Таким образом, у вас есть "реальный" экземпляр и "поддельный интерфейс", и какой фальшивый интерфейс он делает, он служит для вас всей защитой/транзакцией/удалением. Приятно, но трудно понять, и выглядит как ошибка, если вы не разобрались.

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

Таким образом, до сих пор причина в том, что безопасность и здравомыслие. Есть причины, по которым это хорошая практика, но из вашего поста, я вижу, вы уже прочитали все это. Самая важная причина, которую я вижу сегодня, - это показатель WTH/minute, особенно если мы говорим о новых участниках вашего проекта.