Интерфейсы повсюду? - Лучшие практики

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

Я обнаружил, что применение этого шаблона повсеместно преподает младшим разработчикам веревки, подводит меня к успеху по дороге («о, все это тесно связано! Я не могу использовать это!»), И занимает очень мало времени , Просто (и стоит) понять, что мы всегда, все время, имеем дело с контрактами.

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

Но я хотел дотянуться и посмотреть, сможет ли кто-нибудь предоставить некоторые ссылки/экспертные тексты, объясняющие, почему или почему нет.

2
Я думаю, что «абстракция» имеет несколько и разных значений в разработке программного обеспечения. Для меня интерфейсы не имеют ничего общего с абстракциями. Абстракции не имеют ничего общего с деталями реализации. Это связано с дизайном. Концептуализация. То, чего вы могли бы достичь с интерфейсами или без них.
добавлено автор glacier, источник
Главная опасность создания интерфейса из одного класса заключается в том, что вы получите это ужасно неправильно. Представьте себе, если древний австралиец определил интерфейс для IMammal. Все они имеют требуемый метод sizeOfPouch() ...
добавлено автор MrG, источник
Объясните, почему Y выгодно использовать абстрактный класс. Абстракция идентична правильно? Никаких изменений кода. Есть вызовы конструктора в миллионах мест, имея в виду, что классы также не должны предоставлять конструкторы? Инъекция зависимостей намного старше C# и Java.
добавлено автор Frank Hileman, источник
Я не вижу вашей логики. Если API идентичен, swap является бесшовным, независимо от использования интерфейса, конкретного класса или абстрактного класса. Единственное отличие - это конструкция, которая может быть изолирована разными способами, а не только через DI.
добавлено автор Frank Hileman, источник
InterfaceB предоставляет значение только тогда, когда вы используете обе службы одновременно (множественное наследование) в том же процессе. Но вы также можете получить эту выгоду, используя базовый класс.
добавлено автор Frank Hileman, источник
Если вы заменяете один тип другим, вы либо используете базовый класс, либо изменяете исходный тип. Любой язык OO будет работать. Вы описываете ситуацию, когда вам либо нужны оба типа одновременно, либо существуют разные организации, создающие компоненты (плагины).
добавлено автор Frank Hileman, источник
Вы не представили никаких объяснений по этому требованию. Я говорю вам с точки зрения пользователя, единственным отличием между интерфейсом (специализированным классом) и классом является конструктор. Вы должны были бы привести пример, когда это стоило бы миллионам для модификации.
добавлено автор Frank Hileman, источник
В целом, дорогостоящие изменения не являются изменениями имен для типов, а инвазивными изменениями API. DI и интерфейсы ничего не помогают. Ваш сценарий не связан с сохранением работы.
добавлено автор Frank Hileman, источник
Я потратил много времени на устранение лишних интерфейсов, поэтому я назвал его конструкцией культа. Единственное преимущество - увеличить стоимость разработки программного обеспечения - возможно, для подрядчиков и сотрудников, но не для людей, платящих за разработку.
добавлено автор Frank Hileman, источник
@froodley Правильно, но класс на таких языках - это абстракция (предоставленные операции) и реализация в одном текстовом документе. То есть тогда как на других языках они могут быть отдельными, такие языки позволяют объединить их в одну единицу. Они все еще могут быть разделены ... класс может оставить членов нереализованными; если все это так, это эквивалентно интерфейсу без преимуществ множественного наследования.
добавлено автор Frank Hileman, источник
Классы в типах языков, которые вы подразумеваете, являются абстракциями и реализациями этой абстракции. Классы предоставляют «интерфейс» (API). Ключевое слово интерфейса позволяет указать класс без реализации, чтобы обойти ограничения языка. С точки зрения пользователя ни класс, ни интерфейс не лучше или абстрактнее, чем другие. Интерфейсы могут затруднить конструкцию.
добавлено автор Frank Hileman, источник
Кажется, вы не используете ту же терминологию, которая используется в информатике в целом. Классы - это абстракции, даже целые числа и числа с плавающей запятой - это абстракции. Интерфейсы не увеличивают «абстракцию»: более абстрактный тип данных является более общим и выше в иерархии типов; место реализации не имеет значения с точки зрения абстракции.
добавлено автор Frank Hileman, источник
@Meo Я согласен, интерфейсы на таких языках предназначены только для множественного наследования. Но мне не нравится злоупотребление «абстракцией» в вопросе.
добавлено автор Frank Hileman, источник
Что касается «развязки 101» в исходном сообщении, интерфейс, который соответствует публичным членам класса 1: 1, не отделяет ничего, потому что существует только одна реализация (что означает, что в сочетании с одним классом еще), и потому что вы должны обновлять оба одновременно, изменяя общедоступные подписи. В то же время нет никакой пользы в развязывании чего-то, что должно быть связано - развязка - это ситуации, в которых проблема связи является проблемой. Излишние интерфейсы - это форма конструкции куска груза.
добавлено автор Frank Hileman, источник
@froodley Конструктор может быть предоставлен только классом, но класс также не должен предоставлять его. Является ли класс без публичного конструктора «конкретным»? Пользователям все равно, где реализована реализация; они работают только с абстракцией.
добавлено автор Frank Hileman, источник
@froodley Что вы подразумеваете под «бетоном»? Термины в информатике, абстрактном типе данных и уровнях абстракции не имеют ничего общего с ключевым словом «абстрактный» в Java и C #. Ключевое слово лучше назвать «нереализованным» или в случае «неполного» класса. Вы имеете в виду тип данных, который предоставляет конструктор? Абстракция более формально представляет собой набор операций, а также семантику этих операций; на языках, о которых мы говорим, мы можем указать только семантику в документации. Все типы данных являются абстракциями - реализация не учитывается пользователями.
добавлено автор Frank Hileman, источник
Вы запутываете «интерфейс» и «конкрецию» в терминах разработки программного обеспечения с «интерфейсом» и «классом» в Java/C #? Вы можете запрограммировать интерфейс без фактического написания отдельного интерфейса Java .
добавлено автор immibis, источник
Я не согласен с тем, что конкретный класс является абстрактным. Вы имеете в виду, что это часть компьютерного кода, а не автомобиль? Я имею в виду абстракцию в том смысле, что я имею дело с чем-то чисто абстрактным, как набор полей и операций, которые он должен иметь, согласованный способ говорить об объекте, который не зависит от получения какой-либо конкретной реализации. Все, кроме чисто абстрактного класса, уже не является абстракцией, за исключением того, что на самом деле это не автомобиль.
добавлено автор Dave Lau, источник
Абстракция не может быть реализацией по определению.
добавлено автор Dave Lau, источник
альтернатива: сервис X вводится непосредственно повсюду. Он больше не работает. Каждый нисходящий потребитель должен быть изменен, некоторые - в других компаниях, некоторые - в программном обеспечении, разработанном разработчиками, покинувшими компанию.
добавлено автор Dave Lau, источник
Опять же, если вы когда-либо проводили много лет, а миллионы людей обращались к кому-то программированию на ядро ​​YAGNI, вы можете понять, почему я не согласен.
добавлено автор Dave Lau, источник
Что касается культа груза, я действительно не согласен с тем, что это нецелесообразно. Я считаю, что вы правильно относитесь к абстракциям, а не к конкретным реализациям, и что вы говорите, что говорить о настройке URL-адресов вместо жесткого кодирования - это культ груза, потому что они, вероятно, не изменятся.
добавлено автор Dave Lau, источник
Если вы когда-либо ошиблись в том, что ваше программное обеспечение объявлено жестко связанным, и это будет стоить миллионы долларов для развязки, вы поймете, что я отказываюсь разрабатывать тесно связанное программное обеспечение. Работа с интерфейсами, безусловно, отделяет ваше программное обеспечение даже при одной реализации. Любой потребитель может заменить вашу библиотеку другой, которая обеспечивает любую реализацию или фасад над своей собственной реализацией, которая обеспечивает тот же интерфейс. Я действительно не знаю, откуда вы пришли; все это кажется мне ленивым и скользким.
добавлено автор Dave Lau, источник
Все в компьютере - это абстракция.
добавлено автор Dave Lau, источник
Интерфейс является более абстрактным, чем конкретный класс, по определению.
добавлено автор Dave Lau, источник
Это концептуальное представление объекта, а не конкретная реализация этого концептуального представления.
добавлено автор Dave Lau, источник
Если я скажу, что вы должны предоставить мне объект ServiceX, я не могу дать вам объект ServiceY. Компилятор предотвратит это. Если я скажу, что вы должны дать мне объект InterfaceB, вы можете дать мне один.
добавлено автор Dave Lau, источник
Это тривиально увеличивает затраты изначально, экономя миллионы долларов вниз, когда пришло время заменить библиотеку, в которой теперь есть десятки потребителей.
добавлено автор Dave Lau, источник
Если заменить один тип на другой, я ничего не меняю, кроме какой фабрики я предоставляю инжектор в конфиге. Он объединяет еще один класс, который реализует интерфейс B, и никакой код вообще не изменяется.
добавлено автор Dave Lau, источник
Служба X устарела, поскольку бэкэнд-система была заменена. Служба Y создана для выполнения той же цели. Мы предоставляем сервис Z инжектору зависимости, а дети из нескольких библиотек и приложений, ожидающие только службы, которая удовлетворяет интерфейсу B, полностью не затрагиваются.
добавлено автор Dave Lau, источник
На каком языке вы работаете? Вы не можете вводить ServiceY в класс, ожидающий ServiceX на любом строго типизированном языке.
добавлено автор Dave Lau, источник
Мы предоставляем услуги Y *
добавлено автор Dave Lau, источник
@FrankHileman точно, OP в основном делает 2 интерфейса для одной реализации, когда он должен быть обратным - 1 интерфейс для реализации 2+.
добавлено автор Michael, источник
@froodley на языке вы работаете?
добавлено автор Michael, источник

5 ответы

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

Вот почему меня раздражает соглашение C# ICar . Получите этот бессмысленный I шум из моего лица. Java не намного лучше. Конечно, по соглашению я могу назвать интерфейс, абстрактный класс или конкретный класс Car в исходном коде, но если я перехожу от одного к другому, мне нужно перекомпилировать все, что его использует !

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

Кстати, если у вас хорошие тесты, язык с утиным набором текста дает вам все это бесплатно.

Но поскольку я должен использовать эти языки, поскольку я их нахожу, я обычно использую в них. Это означает, что я не пишу drive (Car car) Я пишу диск (DriverControls driverControls) и все, что хочет принять рулевое управление, ускорение и нарушение сообщений по DriverControls может свободно это делать.

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

6
добавлено
В Java ваш интерфейс DriverControls обычно называется Drivable.
добавлено автор Alexei, источник
@froodley Согласен. Это означает, что настоящие дискуссии должны касаться проблем, которые могут быть вызваны, когда вы сначала используете конкретные классы, а затем реорганизуете их на интерфейсы. Трудно это сделать и уважать открытый закрытый принцип. Хуже всего то, насколько легко осознавать, что конкретный статус Car будет распространяться. Я исследовал попытку отладить это, оставаясь бетонным здесь . Это некрасиво.
добавлено автор candied_orange, источник
В основном по причине, которую вы дали, я. Я не хочу иметь дело с какой-то определенной вещью, называемой автомобилем, которая делает что-то конкретным образом. Для меня это всего лишь одноразовый код мусора. Я хочу заниматься взаимодействием с контрактом. Я знаю, что я знаю о .drive() и .steer (), и возвращает мне строку, и мне не нужно знать, это автомобиль или лодка.
добавлено автор Dave Lau, источник

Вам не хватает одного большого куска головоломки:

Использование интерфейсов во всем мире значительно затрудняет перемещение вашего кода

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

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

В принципе, перемещение кода становится все более расстраивающим из-за сверхплотных интерфейсов.

Мое эмпирическое правило: использовать интерфейс, когда у вас действительно есть несколько разных реализаций, а не только ради него .


РЕДАКТИРОВАТЬ:

Мое «намного сложнее», вероятно, было преувеличено. Я просто должен был написать «сложнее» или «неудобно».

Чтобы проиллюстрировать это, в затмении. С помощью метода из класса:

  • Ctrl + клик прыгает внутри метода (1 клик).

С помощью метода из интерфейса это будет:

  • Ctrl + клик
  • перейти наверх
  • щелкните правой кнопкой мыши по имени interace
  • open type explorer
  • выберите класс
  • открытый план
  • перейти к методу

... Итак, да, вы можете сделать это с хорошей поддержкой IDE, но это все еще довольно раздражает.

3
добавлено
Привет, хо! Успокойся, ребята! ;) Мое «намного сложнее», вероятно, было замечено. Я просто должен был написать «сложнее» или «неубедительно». Чтобы проиллюстрировать это, с помощью метода класса в eclipse, Ctrl + click переходит в метод (1 клик). С интерфейсом это будет Ctrl + щелчок, перемещение сверху, правый щелчок по имени interace, открытый тип explorer, выбор класса, открытый контур, переход к методу. Итак, да, вы можете сделать это с поддержкой IDE, но это все равно 7 кликов или около того, что все еще довольно раздражает.
добавлено автор TLS, источник
@froodley: IMHO, добавление интерфейсов систематически просто добавляет бесполезный шум. Он не улучшает развязку и не гарантирует, что базовая реализация будет соответствовать контракту. Это просто добавляет ненужные указания, шумы и раздражает приспешников-разработчиков. Есть много случаев, когда интерфейсы полезны, но систематически это ИМХО просто глупо.
добавлено автор TLS, источник
@froodley Независимо от того, использует ли lib интерфейсы или классы, я привязываюсь к ним. Не важно. Если я вызываю myLib.doThat (someArg) , не имеет значения, является ли myLib интерфейсом или классом. Если я действительно останусь несколько независимым от него, мне придется создать вокруг него обертку. Однако в большинстве случаев добавление таких абстракций является скорее помехой, чем полезной. Довольно редко переключать зависимости, и если вы это сделаете, вы обычно заметите, что ваша обложка не очень подходит для другой библиотеки, что приводит к изменениям в двух местах, а не в одном.
добавлено автор TLS, источник
@froodley Замена зависимости: раз в несколько лет. Навигация/понимание/рефакторинг кода: каждый день. Разместите интерфейсы везде, если вам это нравится, мне все равно, но, пожалуйста, поддержите свои вещи в конечном итоге.
добавлено автор TLS, источник
@Meo здесь мы не говорим о Runnable , это ошибочный пример, похожий на «что, если вы хотите найти конкретный подкласс Object ». Нет проблем с поиском конкретной реализации MyInterface . Если, конечно, вы не решили, что все ваши пользовательские классы реализуют MyInterface без каких-либо причин, но тогда возникают большие проблемы.
добавлено автор Kayaman, источник
@Meo Это было бы реалистично только в ситуации, когда правило «каждый класс должен реализовывать интерфейс», без каких-либо условий о , который интерфейс. Я не вижу такой возможности в профессиональной среде. Я имею в виду, что если мы работаем во враждебной среде, интерфейсы не будут делать ничего хорошего, потому что кто-то может сознательно или неосознанно писать неправильные реализации. Означает ли это, что интерфейсы бесполезны, потому что они не гарантируют правильность реализации?
добавлено автор Kayaman, источник
Любая IDE стоит своей соли знает, как перейти к реализации. Это никоим образом не является допустимым моментом, если вы не используете плохие инструменты.
добавлено автор Kayaman, источник
@Meo Я никоим образом не выступаю за то, чтобы класс every нуждался в реализации интерфейса. Каждому младшему разработчику должно быть понятно, какие классы требуют интерфейс (например, службы), а какие нет (например, объекты, объекты значений). Если нет никакой архитектуры или руководящих принципов, то это не имеет большого значения, так как кодовая база будет в плохом состоянии.
добавлено автор Kayaman, источник
@Meo Я думаю, что пост был отредактирован после моего комментария. Я не сторонник интерфейсов для каждого класса, и я не защищаю архитектуру настолько плохо, что вы не можете следить за тем, что происходит.
добавлено автор Kayaman, источник
@Meo не вкладывает слова в мой рот, а затем говорю «Неправильно». Я говорю, что нет причин избегать интерфейсов с одной реализацией, например. Я говорю, что не все классы реализуют интерфейс, так как это просто глупо (особенно если он заставляет всех классов внедрять Runnable из-за лени). Я говорю, что при принятии дизайнерских решений используйте свой опыт (или попросите кого-то более опытного). Я не уверен, стоит ли цена, о которой вы говорите, стоимость разработки или стоимость исполнения, но в любом случае это незначительно. Это как микро-оптимизация, избегая интерфейсов.
добавлено автор Kayaman, источник
Это абсолютно важно. Если вы можете заменить myLib на someLib, который реализует одну и ту же подпись, не меняя код вообще, тем меньше тратит 2 миллиона долларов, заменяя тысячи жестких ссылок на myLib, то то, что я вам дал, было языком, а не машиной, привязан к вечно. Есть более высокие и более сложные и дорогие земли развязки для достижения еще более слабой связи, но если вы занимаетесь только абстракциями, ваше программное обеспечение по умолчанию очень слабо связано и может быть заменено без каких-либо изменений в потребляющем коде.
добавлено автор Dave Lau, источник
Это тяжелее. Также сложнее не жестко закодировать пароли в кодовой базе или поставить бизнес-логику в своих моделях. Это строгость. Это «вы хотите работать, или нет» для меня.
добавлено автор Dave Lau, источник
Это не бесполезно. Если я передам вам класс или библиотеку, которая занимается только конкрециями, вы плотно связываетесь с моей работой, и мы оба вышли из строя. По моему опыту, это раздражает нетерпеливых младших разработчиков, в то время как опытные разработчики хотят заключать контракты и осознавать, что это самоубийство.
добавлено автор Dave Lau, источник
@ Кайаман, мы увидим, если он был отредактирован, это не так.
добавлено автор Michael, источник
@Kayaman Я имел в виду ваш первый комментарий. Правда в том, что «перемещение кода становится все более расстраивающим из-за сверхплотных интерфейсов». и ни один инструмент не может это изменить. Вы написали, что это неверная точка, что неверно.
добавлено автор Michael, источник
@ Kayaman Нет, вы говорите, что прыгать с «сверхплотных интерфейсов» на реализацию или обратно не стоит. Неправильно.
добавлено автор Michael, источник
@Kayaman, если у каждого класса будет свой собственный интерфейс или нужен самый узкий интерфейс, тогда я согласен с вами в том, что IDE должна справиться с этим просто отлично. И вы знаете, что является самым плотным интерфейсом? Сам класс. Ожидая, что стоимость навигации от переработанных интерфейсов просто наивна.
добавлено автор Michael, источник
@ Кайаман, если вы слишком обобщите все, тогда вы неизбежно столкнетесь с одной и той же проблемой. Если наличие интерфейса является нормой, кто-то рано или поздно будет экономить время и использовать существующий, где они не должны, а затем IDE предложит нелогичные реализации.
добавлено автор Michael, источник
@Kayaman Не, если вы используете плохие абстракции, попробуйте найти эту конкретную реализацию своим интерфейсом Runnable.
добавлено автор Michael, источник

Я согласен с вашим коллегой.

Создание хороших абстракций сложно. Нравится, действительно, НАСТОЯТЕЛЬНО!

Абстракции дополняют программное обеспечение. Они затрудняют навигацию по коду и причине. Они затрудняют изменение, поскольку изменения в абстракциях часто требуют изменений в нескольких местах.

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

Всякий раз, когда вы создаете абстракцию, вам нужно задать себе вопрос: «Стоит ли это усложнять код, чтобы я мог разделить эти штуки?»

3
добавлено
Создание хороших абстракций сложно, потому что они устраняют сложность. Вместо этого добавляются плохие абстракции.
добавлено автор Shizam, источник
@froodley Если ваш интерфейс и класс имеют одну и ту же подпись, вы не отделили ничего, кроме строительства.
добавлено автор Frank Hileman, источник
Создание больших абстракций трудно, создание абстракций, которые служат для развязки, не так уж сложно. Если мои потребители могут заменить мой модуль или класс другим модулем или классом, который может обслуживать одну и ту же подпись, я считаю, что я правильно выполнил эту работу, и они не тесно связаны с тем, что я сделал.
добавлено автор Dave Lau, источник

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

Каждый интерфейс имеет стоимость и ценность, если вы не рассматриваете его и слепо делаете их повсюду, тогда вы делаете это просто неправильно.

1
добавлено
@froodley Контракт - это набор операций и семантики. Интерфейс - это просто набор операций, набор подписи, который выглядит точно так же, как класс, с точки зрения пользователя. Насколько я могу судить, то, что вы называете «конкретным», - это наличие конструктора в классе. Развязка означает, что вы можете изменить API независимо от реализации. Класс может это сделать, интерфейс может это сделать, но реальная развязка означает использование нескольких интерфейсов или динамического языка.
добавлено автор Frank Hileman, источник
@froodley С точки зрения пользователя единственная разница в зависимости от того, что вы называете «конкретным» классом и «интерфейсом», - это зависимость конструктора. Вы можете создать класс, предоставляющий конструктор. Вы не можете создавать специализированные классы, которые не содержат конструктора, такого как интерфейс. Интерфейс и класс идентичны с точки зрения пользователей, в противном случае.
добавлено автор Frank Hileman, источник
Это твой прием, у меня все наоборот. Высокое сцепление концептуально внутри модуля все еще достигается, когда вы имеете дело с контрактами, которые тесно связаны. Я придерживаюсь мнения, что построение на основе контрактов все время устраняет любую двусмысленность и обеспечивает правильный вид мышления, в то же время приводит к высокоразвиваемой кодовой базе «дешево» по сравнению с попыткой разделить позже, когда многие потребители уже зависят от вашего конкреции. Но опять же, я ищу некоторые ссылки на чтение материала по этому вопросу.
добавлено автор Dave Lau, источник
Интерфейс - это контракт. Класс - это машина, которая производит некоторую реализацию этого контракта. Они очень разные. Я вовсе не убежден в том, что дело в конкретных машинах такое же, как и в контрактах.
добавлено автор Dave Lau, источник

Я программирую бизнес-приложения данных

Обычно они не подходят для классического «истинного» ООП, где объект реализует свое собственное поведение из-за всех бизнес-правил, которые зависят от текущего подключенного пользователя и т. Д. Вместо этого у меня есть известная анемичная модель + услуги, потому что я не нашел ничего, что больше подходит для моих потребностей, за исключением некоторых независимых технических компонентов.

У моих сервисов всегда есть интерфейсы, потому что, даже если у меня будет одна реализация, будет время, когда я хочу издеваться над ними. Я немного отрисовываю немного, но не слишком много, поскольку в то время, когда я это делаю, я не знаю, сколько мне нужно, и как это сделать правильно, и мое время лучше, чем тратить время на это (YAGNI/KISS ).

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

Примечание. Я использую регулярное имя для интерфейса моих сервисов, которые я использую (нет «я» или что-то еще), потому что потребителю этой службы действительно неважно, что они являются интерфейсами, как указано @candied_orange

0
добавлено
В Java вы можете издеваться над интерфейсами точно так же, как с ними (используя Mockito и т. Д.), Если вы не захотите, конечно, реализовать класс вручную.
добавлено автор Michael, источник