Почему всегда существуют единые интерфейсы реализации в сервисе и дао?
Я работал/видел несколько проектов веб-приложений 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, особенно если мы говорим о новых участниках вашего проекта.