Следует ли создавать интерфейс, когда (в настоящее время) будет только один класс, который его реализует? - PullRequest
6 голосов
/ 06 апреля 2009

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

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

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

Ответы [ 6 ]

8 голосов
/ 06 апреля 2009

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

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

3 голосов
/ 06 апреля 2009

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

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

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

2 голосов
/ 06 апреля 2009

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

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

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

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

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

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

2 голосов
/ 06 апреля 2009

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

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

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

2 голосов
/ 06 апреля 2009

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

1 голос
/ 06 апреля 2009

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

...