Интерфейсы против открытых членов класса - PullRequest
3 голосов
/ 15 июля 2010

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

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

Спасибо.

Ответы [ 8 ]

6 голосов
/ 15 июля 2010

Применение любого шаблона проектирования или идеи без размышлений, просто потому, что кто-то сказал вам, что это хорошая практика, является плохой идеей.

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

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

3 голосов
/ 15 июля 2010

Интерфейсы являются мощным инструментом для абстракции. С их помощью вы можете более свободно заменять (например) тестовые классы и тем самым отделять свой код. Они также способ сузить область вашего кода; вам, вероятно, не нужен полный набор функций данного класса в определенном месте - какие именно функции вам нужны? Это ориентированный на клиента способ мышления об интерфейсах.

1 голос
/ 16 июля 2010

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

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

OTOH, если у клиента есть прямой доступ к открытым методам членства в коде, это вполне нормально, если вы действительноне предвидите никаких изменений в классе, которые также могут потребовать изменений в клиенте.В любом случае, однако, иметь открытые поля-члены я считаю нехорошо.Это очень жесткая связь!Вы в основном разоблачаете архитектуру своего класса и ставите клиентский код в зависимость от него.Завтра, если вы поймете, что другая структура данных для определенного поля будет работать лучше, вы не сможете изменить ее, не изменив и клиентский код.

1 голос
/ 15 июля 2010

Все дело в ожидании и подготовке к переменам.

Один из подходов, который некоторые используют (и я не обязательно его защищаю), заключается в создании IThing и ThingFactory.

Весь код будет ссылаться на IThing (вместо ConcreteThing).Все создание объекта может быть выполнено с помощью метода Factory.

ThingFactory.CreateThing (некоторые параметры).

Итак, сегодня у нас есть только AmericanConcreteThing.И возможно, что нам никогда не понадобится другой.Однако, если опыт меня чему-то научил, так это то, что нам ВСЕГДА понадобится другое.

Вам, возможно, не нужен EuropeanThing, но TexasAmericanThing вполне возможна.

Итак, чтобы минимизировать влияние на мой код, я могу изменить строку создания на:

ThingFactory.CreateThing (Account) и Create my class TexasAmericanThing: IThing.

Кроме создания класса, единственным изменением является ThingFactory, который потребует изменения с

public static IThing CreateThing(Account a)
{ 
   return new AmericanThing();
}

to 

public static IThing CreateThing(Account a)
{
   if (a.State == State.TEXAS) return new TexasAmericanThing();
   return new AmericanThing();
}
1 голос
/ 15 июля 2010

Модульные тесты.

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

0 голосов
/ 15 июля 2010

Мне нравятся интерфейсы:
* для определения договора между частями / модулями / подсистемами или сторонними системами
* при наличии сменных состояний или алгоритмов (состояние / стратегия)

0 голосов
/ 15 июля 2010

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

0 голосов
/ 15 июля 2010

Я в основном использую интерфейсы для IoC, чтобы включить модульное тестирование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...