Программирование на интерфейс. Как решить, где это нужно? - PullRequest
10 голосов
/ 04 декабря 2008

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

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

Всегда можно утверждать, что, поскольку приложение усложняется, и я передаю объекты, было бы больше смысла передавать тип (интерфейс), чем реализацию. Итак, я должен ждать, пока приложение станет сложным или использовать его сразу? Мне интересно, что лучшая практика может оказаться "этот парень закончил делать вещи".

Ответы [ 10 ]

7 голосов
/ 04 декабря 2008

Если вы когда-нибудь заинтересуетесь разработкой через тестирование, необходимость в «программировании интерфейса» действительно станет очевидной. Если вы хотите, чтобы класс тестировался изолированно от его зависимостей, вам нужно обойти интерфейсы вместо объектов.

7 голосов
/ 04 декабря 2008

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

4 голосов
/ 04 декабря 2008

Простой пример, который открыл мне глаза на интерфейсы, это

class SimpleClass
{
  public int A { get; set; }
  public int B { get; set; }
  public int C { get; set; }
}

List<SimpleClass> Calc(IEnumerable<SimpleClass> list)
{
  foreach(SimpleClass item in list)
  {
     item.C = item.A * item.C:
  }
  return list.ToList();
}

Обратите внимание на входной параметр IEnumerable. Используя это, я могу передать любую коллекцию, которая реализует IEnumerable в качестве параметра in. List<SimpleClass>, SimpleClass[], Collection<SimpleClass>.

Интерфейс IEnumerable гарантирует мне, что я могу использовать цикл foreach, и таким образом я сделал свою функцию более общей, и у меня будет меньше шансов изменить этот код, поскольку вероятность того, что IEnumerable изменится, меньше, чем f .ex. Список изменений.

3 голосов
/ 04 декабря 2008

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

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

3 голосов
/ 04 декабря 2008

Если есть большая вероятность, что приложение станет более сложным, проще настроить леса раньше, чем позже. Тем не менее, если приложение не сложное и маловероятно, что оно не станет сложным, ROI может отсутствовать. Вы всегда можете выполнить рефакторинг позже.

1 голос
/ 06 декабря 2008

Посмотрите книгу Шаблоны проектирования Head-First ... вы увидите хорошие аргументы в пользу использования интерфейсов, которые не имеют ничего общего с TDD или полиморфизмом.

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

Если ваш объект Employee имеет ссылку на интерфейс IExpenseCalculator, вы можете назначить ему калькулятор менеджера или калькулятор сотрудника во время выполнения. Вызов Employee.GetExpenses () даст вам другой рассчитанный результат для менеджера, чем для обычного сотрудника. Внутренне код будет выглядеть так:

public class Employee {
  private IExpenseCalculator expenses;

  public ExpenseSheet GetExpenses() {
    return expenses.CalcExpenses();
  }
}

В этом примере предполагается, что «расходы» представлены как свойство, и что в IExpenseCalculator есть метод для CalcExpenses ().

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

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

1 голос
/ 04 декабря 2008

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

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

Наконец, если вам нужно изменить свой код, чтобы использовать SuperEmployee вместо Employee, если вы все время использовали интерфейсы, все, что вам нужно было бы сделать, - это чтобы SuperEmployee реализовал IEmployee, и вы будете настроены.

1 голос
/ 04 декабря 2008

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

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

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

1 голос
/ 04 декабря 2008

Обычно я так думаю - только две вещи отделяют интерфейс от реализации:

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

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

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

1 голос
/ 04 декабря 2008

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

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