Почему всегда есть единственные интерфейсы реализации на уровнях обслуживания и дао? - PullRequest
31 голосов
/ 19 января 2012

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

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

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

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

    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 на основе интерфейсов - это ДИЗАЙН, за которым следуют все - они упоминают о лучших методах Spring, ООП, DDD и т. Д. Но я все еще не получайте прагматическую причину наличия такого большого количества интерфейсов в изолированном приложении.

Ответы [ 2 ]

16 голосов
/ 19 января 2012

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

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

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

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

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

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

16 голосов
/ 19 января 2012

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

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

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

...