Что некоторые преимущества к использованию интерфейса в C#?

Если вы загружаете jQuery в нижней части BODY, но у вас возникают проблемы с кодом, который записывает jQuery (< func>) или jQuery (document) .ready (< func>), посмотрите jqShim на Github.

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

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

21
задан Andrew Siemer 23 June 2009 в 23:01
поделиться

10 ответов

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

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

Widget w = new Widget();

, я бы сказал

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

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

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

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

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

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

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

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

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

16
ответ дан 29 November 2019 в 21:21
поделиться

Базовым случаем является случай "IWriter".

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

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

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

7
ответ дан 29 November 2019 в 21:21
поделиться

Пример. Рассмотрим приложение MDI, которое показывает отчеты, в основном есть два разных типа отчетов. Диаграмма и сетка. Мне нужно сохранить эти отчеты в формате 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
ответ дан 29 November 2019 в 21:21
поделиться

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

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

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

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

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

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

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

и меня не волнует, какие будущие классы Foo могут наследовать или выглядеть внутренне, если они имеют fn x fn y и z. Это делает структуру более гибкой и открытой для будущих дополнений.

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

и меня не волнует, какие будущие классы Foo могут наследовать или выглядеть внутренне, если они имеют fn x fn y и z. Это делает структуру более гибкой и открытой для будущих дополнений.

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

1
ответ дан 29 November 2019 в 21:21
поделиться

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

0
ответ дан 29 November 2019 в 21:21
поделиться

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

0
ответ дан 29 November 2019 в 21:21
поделиться

Простой ответ, основанный на первых принципах:

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

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

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

0
ответ дан 29 November 2019 в 21:21
поделиться

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

Вы можете сделать так, чтобы при загрузке подключаемого модуля у него должен был быть метод 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, а затем вы создаете его экземпляр один раз, вы можете передать его всем подключаемым модулям после инициализации, и они могут использовать любые службы, которые вы определили в интерфейсе.

0
ответ дан 29 November 2019 в 21:21
поделиться

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

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

6
ответ дан 29 November 2019 в 21:21
поделиться

good article.

An interface is a contract that guarantees to a client how a class or struct will behave.

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

This might be the clearest easiest way of explaining that I have come across:

"The answer is that they provide a fairly type-safe means of building routines that accept objects when you don't know the specific type of object that will be passed ahead of time. The only thing you know about the objects that will be passed to your routine are that they have specific members that must be present for your routine to be able to work with that object. Лучший пример необходимости интерфейсов, который я могу привести, - это командная среда. Интерфейсы помогают определить, как разные компоненты взаимодействуют друг с другом. Используя интерфейс, вы исключаете возможность того, что разработчик неверно истолкует, какие члены он должен добавить к типу или как они будут вызывать другой тип, определяющий интерфейс. Без интерфейса ошибки закрадываются в систему и не проявляются до времени выполнения, когда их трудно найти. С интерфейсами ошибки в определении типа обнаруживаются немедленно во время компиляции, что значительно снижает затраты "

0
ответ дан 29 November 2019 в 21:21
поделиться
Другие вопросы по тегам:

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