Хороший чехол для интерфейсов - PullRequest
11 голосов
/ 26 августа 2009

Я работаю в компании, где некоторым требуется обоснование использования интерфейса в нашем коде (Visual Studio C # 3.5).

Я хотел бы попросить рассуждения Iron Clad, для которых необходимы интерфейсы. (Моя цель - ДОКАЗАТЬ, что интерфейсы являются нормальной частью программирования.)

Мне не нужно убеждать, мне просто нужен хороший аргумент, чтобы убедить других.

Тип аргумента, который я ищу, основан на фактах, а не на сравнении (т. Е. «Потому что .NET-библиотека их использует» основана на сравнении).

Аргумент против них таков: если класс правильно настроен (с его открытыми и закрытыми членами), то интерфейс - это просто дополнительные издержки, потому что те, которые используют класс, ограничены открытыми членами. Если вам нужен интерфейс, реализованный более чем одним классом, просто настройте наследование / полиморфизм.

Ответы [ 17 ]

26 голосов
/ 26 августа 2009

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

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

Определение поведения, которое может применяться ко многим различным классам, что позволяет использовать их взаимозаменяемо, даже если между классами нет никакой связи (кроме определенного поведения). Например, класс Horse и Bicycle могут иметь метод Ride. Вы можете определить интерфейс IRideable, который определяет поведение Ride, и любой класс, использующий это поведение, может использовать объект Horse или Bicycle без принудительного наследования между ними.

18 голосов
/ 26 августа 2009

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

Рассмотрим следующий код:

interface ICrushable
{
  void Crush();
}

public class Vehicle
{
}

public class Animal
{
}

public class Car : Vehicle, ICrushable
{
  public void Crush()
  {
     Console.WriteLine( "Crrrrrassssh" );
  }
}

public class Gorilla : Animal, ICrushable
{
  public void Crush()
  {
     Console.WriteLine( "Sqqqquuuuish" );
  }
}

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

10 голосов
/ 26 августа 2009

В дополнение к вещам, объясненным в других ответах, interfaces позволяет имитировать множественное наследование в .NET, которое иначе не разрешено.

Увы, как кто-то сказал

В технологии доминируют два типа людей: те, кто понимает, что им не удается, и те, кто управляет тем, что они не понимают.

6 голосов
/ 26 августа 2009

Чтобы включить модульное тестирование класса.

Для эффективного отслеживания зависимостей (если интерфейс не извлечен и не затронут, возможно, изменилась только семантика класса).

Потому что нет времени выполнения.

Чтобы включить внедрение зависимостей.

... и, возможно, потому что это чертовски 2009 год, а не 70-е годы, и современные дизайнеры языка на самом деле имеют представление о том, что они делают?

Не то чтобы интерфейсы должны создаваться на каждом интерфейсе класса: только те, которые являются центральными для системы, и которые, вероятно, претерпят значительные изменения и / или расширение.

4 голосов
/ 26 августа 2009

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

Подумайте о чем-то, что Serializable, на самом деле не имеет смысла (с точки зрения дизайна / моделирования) иметь базовый класс с именем Serializable, так как не имеет смысла говорить что-то как Serializable. Наличие чего-либо реализующего интерфейс Serializable имеет больше смысла в том, чтобы сказать «это то, что может сделать класс, а не то, что класс»

3 голосов
/ 26 августа 2009

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

Как вы доказываете, что вам нужны интерфейсы в коде, который вы пишете на своем рабочем месте? Находя место в вашей реальной кодовой базе (не в некотором коде от чьего-либо продукта, и, конечно, не в каком-нибудь игрушечном примере о Duck, реализующем метод makeNoise в IAnimal), где решение на основе интерфейса лучше, чем решение на основе наследования. Покажите своим боссам проблему, с которой вы сталкиваетесь, и спросите, имеет ли смысл изменить руководящие принципы для приспособления к подобным ситуациям. Это обучающий момент, когда все смотрят на одни и те же факты, а не бьют друг друга по голове общностями и спекуляциями.

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

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

3 голосов
/ 26 августа 2009

Интерфейсы вообще не «нужны», это дизайнерское решение. Я думаю, вам нужно убедить себя, почему в каждом конкретном случае полезно использовать интерфейс, потому что при добавлении интерфейса возникают накладные расходы. С другой стороны, чтобы противопоставить аргумент против интерфейсов, потому что вы можете «просто» использовать наследование: наследование имеет свои недостатки, одним из них является то, что - по крайней мере, в C # и Java - вы можете использовать наследование только один раз (одиночное наследование); но второе - и, возможно, более важное - это то, что наследование требует, чтобы вы понимали работу не только родительского класса, но и всех классов-предков, что делает расширение сложнее, но и более хрупким, потому что изменение в родительском классе ' Реализация может легко сломать подклассы. В этом суть аргумента «композиция поверх наследования», которому научила нас книга GOF.

2 голосов
/ 26 августа 2009
  • Test Driven Development
  • Модульное тестирование

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

2 голосов
/ 26 августа 2009
  • Вы можете реализовать несколько интерфейсов. Вы не можете наследовать от нескольких классов.
  • .. вот и все. Пункты, которые другие делают о развязке кода и разработке через тестирование, не доходят до сути вопроса, потому что вы можете делать это и с абстрактными классами.
2 голосов
/ 26 августа 2009

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

В данном случае мы говорим: «эта вещь может быть перечислена, но это не единственная ее определяющая характеристика».

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

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

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

...