Вопрос по c#, oop – Каковы некоторые преимущества использования интерфейса в C #?

21

Я был вынужден участвовать в программном проекте на работе несколько лет назад и был вынужден быстро изучать C #. Мой опыт программирования слабый (классический ASP).

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

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

Спасибо Кевину

Глянь сюда Stackoverflow.com / вопросы / 56867 / интерфейс-против-базового класса и здесь / Stackoverflow.com вопросы / 444245 / ... и поиск "интерфейс C #" для получения дополнительной информации. Marc

Ваш Ответ

10   ответов
16

как что-то должно работать. Думайте об этом как о контракте или шаблоне. Это ключ к таким вещам, как Inverson of Control или Depenancy Injection.

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

Widget w = new Widget();

Я бы сказа

IWidget w = ObjectFactory.GetInstance<IWidget>();

Это очень мощно в том смысле, что мой код не обязательно говорит о том, что на самом деле является виджетом. Он просто знает, что может делать виджет на основе интерфейса IWidget.

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

Кроме того, поскольку я использую контейнер IoC, я могу предоставить в приложение новые интересные функции, такие как написание трех разных способов кеширования данных. Я могу иметь локальный кеш разработчика с помощью такого инструмента, как Lucene.NET для локального кеша. У меня может быть сервер разработки, использующий кеш .NET, который отлично работает на одном компьютере. И тогда у меня может быть третий вариант для моих производственных серверов, использующих слой кеша, такой как MemCache Win32 или Velocity. Пока все три реализации кэширования соответствуют одному и тому же интерфейсу, их фактическая реализация не касается меня (или моего кода) вообще. Я просто прошу StructureMap перейти к реализации текущей среды, а затем приступить к работе.

Если вы вообще используете Dependency Injection, то здесь также пригодятся интерфейсы с контейнером IoC, таким как StructureMap, в котором я могу объявить использование класса через интерфейс в конструкторе моего класса.

public class Widget(IWidgetRepository repository, IWidgetService service) : IWidget
{
    //do something here using my repository and service
}

А потом, когда я создаю экземпляр Widget с помощью StructureMap, например,

IWidget widget = ObjectFactory.GetInstance<IWidget>();

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

Все из простого определения интерфейсов и их умного использования!

7

Предположим, вы создаете класс, который может записывать в консоль, и в нем есть все виды полезных функций, таких как write () и peek ().

Затем вы хотели бы написать класс, который может писать на принтер, поэтому вместо того, чтобы изобретать новый класс, вы используете интерфейс IWriter.

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

6

Один простой ответ: Используйте интерфейсы для программирования против Контракт а нереализаци.

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

1

которое показывает отчеты, в основном это 2 разных типа отчетов. Диаграмма и сетка. Мне нужно сохранить эти отчеты в формате PDF и отправить их кому-нибудь по почте. Обработчик события для меню, которое пользователь щелкает, чтобы сохранить отчет в PDF, может сделать это:

void ExportPDF_Clicked(...) {
   if(currentDocument is ChartReport) {
      ChartReport r = currentDocument as ChartReport;
      r.SavePDF();
   } else if(currentDocument is GridReport) {
     GridReport r = currentDocument as GridReport;
      r.SavePDF();
   }
}

Я лучше сделаю так, чтобы мои ChartReport и GridReport реализовали этот интерфейс:

public interface Report {
  void MailTo();
  void SavePDF();
}

Теперь я могу сделать:

void ExportPDF_Clicked(...) {
   Report r = currentDocument as Report;
   r.SavePDF();
}

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

1

и я призываю вас взглянуть на них.

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

Допустим, у меня есть класс Foo с функциями x и y и свойством z, и я строю свой код вокруг него.

Если я найду лучший способ сделать Foo, или другой тип Foo требует реализации, я, конечно, могу расширить базовый класс Foo до FooA, FooB, MyFoo и т. Д., Однако для этого потребуется, чтобы все Foos имели одинаковую функциональность ядра. или, действительно, любые будущие создатели Foo имеют доступ к базовому классу Foo и понимают его внутреннюю работу. В C # это означало бы, что будущие Foos не смогут наследовать ни от чего другого, кроме Foo, поскольку C # не поддерживает множественное наследование.

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

Использование интерфейса IFoo просто заявляет «контракт», который необходим классу для работы в моей среде Foo, и мне все равно, что любые будущие классы Foo могут наследовать или выглядеть внутренне, если у них есть fn x fn y и з. Это делает структуру намного более гибкой и открытой для будущих дополнений.

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

0

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

0

Интерфейс - это контракт, который гарантирует клиенту поведение класса или структуры.

http: //www.codeguru.com/csharp/csharp/cs_syntax/interfaces/article.php/c756

Это самый простой способ объяснить, с чем я столкнулся:

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

0

когда вы наследуете от интерфейса, это заставляет вас реализовать все методы, определенные в интерфейсе. С другой стороны, это также хороший способ ввести множественное наследование, которое не поддерживается для обычных классов.http: //msdn.microsoft.com/en-us/library/ms173156.asp

0

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

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

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

0

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

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

public interface IServices
{
    DataManager Data { get; set; }
    LogManager Log { get; set; }
    SomeOtherManager SomeOther { get; set; }
}

public class MrPlugin
{
    public void Init(IServices services)
    {
        // Do stuff with services
    }
}

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

Похожие вопросы