Должны ли вы создавать интерфейс, когда (в настоящее время) будет только один класс, который его реализует?

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

Программирование интерфейса обычно кажется разумным советом, но тут есть YAGNI...

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


person Davy8    schedule 06.04.2009    source источник


Ответы (6)


Это всегда зависит от ситуации. Если вы ЗНАЕТЕ, что будет другой класс, использующий интерфейс, тогда да, создайте класс интерфейса, чтобы сэкономить время позже. Однако, если вы не уверены (а в большинстве случаев это не так), подождите, пока вам это не понадобится.

Теперь это не означает игнорировать возможность интерфейса - подумайте об общедоступных методах объекта и тому подобном с прицелом на создание интерфейса позже, но не загромождайте свою кодовую базу тем, что вам на самом деле НЕ НУЖНО.

person Michael Kohne    schedule 06.04.2009
comment
YAGNI, тебе это не понадобится -› тебе это не понадобится - person Robert Gould; 06.04.2009
comment
Точно. Каждый раз, когда я когда-либо вставлял интерфейсы или что-то еще «на всякий случай», они оказывались нужными ровно никогда. Но ваш пробег может отличаться. - person Michael Kohne; 06.04.2009

Всегда будет тест, который его использует, верно (вы делаете модульные тесты, не так ли?). Это означает, что его всегда используют N + 1 класс, где N — количество классов, использующих ваш класс в приложении.

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

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

person topchef    schedule 06.04.2009
comment
Что, если класс настолько прост, что фиктивный объект не нужен для модульного тестирования (т. е. он достаточно прост, чтобы просто использовать реальный объект)? - person Davy8; 06.04.2009
comment
Я никогда ничего не говорил о фиктивных объектах, не так ли :-)? Все, что я говорю, что количество классов, которые его используют, всегда + 1 (тест). И я согласен, что интерфейсы можно внедрить позже простым рефакторингом. - person topchef; 06.04.2009
comment
+1: Injection Dependency Injection определенно является драйвером для использования интерфейса. - person Richard; 06.04.2009

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

Например, команда библиотеки базовых классов .NET Framework признала преждевременное проектирование ICollection, когда оно включало свойство SyncRoot. Для более позднего универсального ICollection<T> они решили удалить его (http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx).

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

person Mark Cidade    schedule 06.04.2009

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

person Bill the Lizard    schedule 06.04.2009

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

Наличие семантики IContainer (контракта) — довольно плохая причина для создания интерфейса из вашей папки; лучше, чтобы ваша папка (если она выполняет какую-либо нетривиальную логику) «реализовала» (вероятно, уже существующий) интерфейс IContainer или ICollection в основных структурах вашего языка.

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

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

Как правило, для любого I у вас должна быть как минимум пара конкретных классов (с более осмысленными именами, отличными от IImpl или ).

Надеюсь, это поможет.

person alphazero    schedule 06.04.2009
comment
Эта штука съела мои угловые скобки: для любых имен Ixxx... кроме IxxxImpl или XXX. - person alphazero; 06.04.2009
comment
SO преобразует ваши угловые скобки < >, как если бы это был стиль html. Чтобы избежать этого, используйте обратные кавычки вокруг символа, - person Kyle Baran; 14.05.2014

Многие люди уже дали очень дельные советы. Я хотел бы добавить одну вещь: если вы хотите избежать прямых жестких зависимостей от конкретных классов, тогда интерфейсы помогут, обеспечивая слабую связь. Если вы создаете архитектуру, основанную на подключаемых модулях, то интерфейсы — это, безусловно, то, что вам нужно. Кроме того, если вы планируете писать модульные тесты одновременно или позже, вы, вероятно, заметите, что код, который вызывает класс (ы) вашей папки, должен иметь конкретную реализацию, чтобы вызывающий код можно было тестировать. . Если ваша конкретная реализация класса (ов) папки, в свою очередь, взаимодействует с БД или службой, вам также потребуется перенести это в ваши тесты, что очень быстро станет громоздким. Просто мои 2 цента.

person Abhijeet Patel    schedule 06.04.2009