Что это значит для "программирования на интерфейсе"?

первая вещь - не следует ли включать их в другом порядке?

что-то вроде этого должно работать:

<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js"></script>
<script>jQuery.fn.validate || document.write('<script src="js/jquery.validate.min.js">\x3C/script><script src="js/jquery.validate.unobtrusive.min.js">\x3C/script>'</script>

то, что я здесь делаю, просто проверяет, был загружен первый плагин (проверка jQ). путем проверки статической функции validate объекта jQuery.fn. Я не могу проверить второй скрипт таким же образом, потому что он ничего не добавляет, просто проксирует существующие методы, поэтому легче предположить, что если первый работает, второй тоже будет работать - в конце концов, они предоставляются тот же CDN.

772
задан Dale Burrell 22 January 2019 в 03:45
поделиться

16 ответов

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

, Когда я сначала начал представляться интерфейсам, я также был смущен их уместностью. Я не понял, почему Вам были нужны они. Если мы используем язык как Java или C#, у нас уже есть наследование, и я просмотрел интерфейсы как более слабый форма наследования и думал, "почему беспокойство?" В некотором смысле я был прав, можно думать об интерфейсах как о виде слабой формы наследования, но кроме того я наконец понял их использование в качестве конструкции языка путем размышления о них как о средстве классификации общих черт или поведений, которые были показаны потенциально многими несвязанными классами объектов.

, Например - говорят, что Вы имеете игру SIM и имеете следующие классы:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

Очевидно, эти два объекта не имеют ничего общего с точки зрения прямого наследования. Но, Вы могли сказать, что они являются оба раздражающими.

Скажем, наша игра должна иметь своего рода случайное вещь , который раздражает игровую консоль, когда они едят ужин. Это могло быть HouseFly или Telemarketer или оба - но как Вы допускаете обоих с единственной функцией? И как Вы спрашиваете каждый другой тип объекта "сделать их раздражающую вещь" таким же образом?

ключ для понимания - то, что и Telemarketer и HouseFly совместно используют общее свободно интерпретируемое поведение даже при том, что они - ничто одинаково с точки зрения моделирования их. Так, давайте сделаем интерфейс, который оба могут реализовать:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

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

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

Здесь у нас есть столовая, которая принимает много небольших ресторанов, и много вредителей - отмечают использование интерфейса. Это означает, что в нашем небольшом мире, члене эти pests массив мог на самом деле быть Telemarketer объект или HouseFly объект.

ServeDinner метод называют, когда обед подан, и наши люди в столовой, как предполагается, едят. В нашей небольшой игре именно тогда наши вредители делают свою работу - каждый вредитель проинструктирован для раздражения посредством эти IPest интерфейс. Таким образом мы можем легко иметь и Telemarketers и HouseFlys быть раздражающими каждым из их собственных способов - мы заботимся только, что у нас есть что-то в эти DiningRoom объект, который является вредителем, мы действительно не заботимся о том, что это, и они могли не иметь ничего общего с другим.

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

1546
ответ дан Murat Yıldız 22 January 2019 в 03:45
поделиться

В Java эти реальные классы вся реализация интерфейс CharSequence:

CharBuffer, Строка, StringBuffer, StringBuilder

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

все же каждый из этих классов способен к подходили реализации методов интерфейса CharSequence:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

В некоторых случаях классы Библиотеки классов Java, которые раньше принимали Строку, были пересмотрены, чтобы теперь принять интерфейс CharSequence. Таким образом, если у Вас есть экземпляр StringBuilder, вместо того, чтобы извлечь Строковый объект (что означает инстанцировать нового экземпляра объекта), может вместо этого просто передать сам StringBuilder, поскольку это реализует интерфейс CharSequence.

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

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Писатель

2
ответ дан RogerV 22 January 2019 в 03:45
поделиться

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

, Например, у меня мог быть интерфейс перемещения. Метод, который заставляет что-то 'переместиться' и любой объект (Человек, Автомобиль, CAT), который реализует интерфейс перемещения, мог быть передан в и сказан переместиться. Без метода каждое знание типа класса это.

3
ответ дан Damien 22 January 2019 в 03:45
поделиться

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

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

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

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

3
ответ дан Matt Fenwick 22 January 2019 в 03:45
поделиться

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

// if I want to add search capabilities to my application and support multiple search
// engines such as google, yahoo, live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

тогда я мог создать GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider и т.д.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

тогда создают JpegImageLoader, GifImageLoader, PngImageLoader, и т.д.

, Большинство дополнений и сменных систем отделываются от интерфейсов.

Другое популярное использование для шаблона Репозитория. Скажите, что я хочу загрузить список почтовых индексов из других источников

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

тогда, я мог создать XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, и т.д. Для моих веб-приложений, я часто создаю репозитории XML вначале, таким образом, я могу разбудить что-то и работающий до Базы данных Sql, являющейся готовым. Как только база данных готова, я пишу SQLRepository для замены версии XML. Остальная часть моего кода остается неизменной, так как это выполняет soley прочь интерфейсов.

Методы могут принять интерфейсы, такие как:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}
12
ответ дан Todd Smith 22 January 2019 в 03:45
поделиться

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

4
ответ дан edgi 22 January 2019 в 03:45
поделиться

Программирование к Интерфейсам является потрясающим, оно способствует слабой связи. Как @lassevk упомянутый, Инверсия Управления является большим использованием этого.

, Кроме того, изучите ТВЕРДЫЕ принципалы . вот видео серия

, Она проходит кодированное твердое (сильно связанный пример) тогда смотрит на интерфейсы, наконец прогрессируя до инструмента МОК/DI (NInject)

8
ответ дан dbones 22 January 2019 в 03:45
поделиться

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

8
ответ дан Kevin Le - Khnle 22 January 2019 в 03:45
поделиться

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

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

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

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

10
ответ дан Ed S. 22 January 2019 в 03:45
поделиться

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

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

РЕДАКТИРОВАНИЕ: Ниже ссылка на статью, где Erich Gamma обсуждает свою кавычку, "Программа к интерфейсу, не реализация".

http://www.artima.com/lejava/articles/designprinciples.html

36
ответ дан tvanfosson 22 January 2019 в 03:45
поделиться

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

Рассматривают (в Java), эти List интерфейс по сравнению с ArrayList и LinkedList реальные классы. Если все, о чем я забочусь, - то, что у меня есть структура данных, содержащая несколько элементов данных, к которым я должен получить доступ через повторение, я выбрал бы List (и это составляет 99% времени). Если я знаю, что мне нужно постоянно-разовый, вставляют/удаляют или от конца списка, я мог бы выбрать LinkedList конкретная реализация (или более вероятно, используйте интерфейс Queue ). Если бы я знаю, что мне нужен произвольный доступ индексом, я выбрал бы ArrayList реальный класс.

69
ответ дан Lucky 22 January 2019 в 03:45
поделиться

Определенный пример, который я раньше давал студентам, - то, что они должны записать

List myList = new ArrayList(); // programming to the List interface

вместо [1 117]

ArrayList myList = new ArrayList(); // this is bad

, Они смотрят точно то же в короткой программе, но если Вы продолжаете использовать myList 100 раз в Вашей программе, можно начать видеть различие. Первое объявление гарантирует, чтобы Вы только назвали методы на myList, которые определяются List интерфейс (так никакой ArrayList определенные методы). При программировании к интерфейсу этого пути позже можно решить, что Вам действительно нужно

List myList = new TreeList();

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

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

public ArrayList doSomething(HashMap map);

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

public List doSomething(Map map);

Теперь не имеет значения, какой List Вы возвращаете, или в каком Map передается в качестве параметра. Изменения, которые Вы вносите в doSomething метод, не вынудят Вас изменить код вызова.

258
ответ дан Bill the Lizard 22 January 2019 в 03:45
поделиться

Необходимо изучить Инверсию Управления:

В таком сценарии, Вы не записали бы это:

IInterface classRef = new ObjectWhatever();

Вы записали бы что-то вроде этого:

IInterface classRef = container.Resolve<IInterface>();

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

, Если мы покидаем МОК от таблицы, можно записать код, который знает, что это может говорить с объектом , который делает что-то определенное , но не, какой тип объекта или как это делает это.

Это пригодилось бы когда передающие параметры.

Что касается Вашего заключенного в скобки вопроса "Кроме того, как Вы могли записать метод, который берет в объекте, который реализует Интерфейс? Это возможно?", в C# Вы просто использовали бы интерфейсный тип для типа параметра, как это:

public void DoSomethingToAnObject(IInterface whatever) { ... }

Это включает право, "говорят с объектом, который делает что-то определенное". Метод, определенный выше, знает, что ожидать от объекта, что это реализует все в IInterface, но это не заботится, какой тип объекта это, только что это придерживается контракта, который является, каков интерфейс.

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

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

Позволяют мне дать Вам конкретный пример.

у Нас есть сделанная на заказ система перевода для форм окон. Эта система циклы посредством средств управления на форме и переводит текст в каждом. Система знает, как обработать основные средства управления, как the-type-of-control-that-has-a-Text-property, и подобный основной материал, но для чего-либо основного, это терпит неудачу.

Теперь, так как средства управления наследовались предопределенным классам, что мы не имеем никакого контроля, мы могли сделать одну из трех вещей:

  1. поддержка Сборки нашей системы перевода для обнаружения конкретно, какой тип управления это работает с и переводит корректные биты (кошмар обслуживания)
  2. , Встраивает поддержку в базовые классы (невозможный, так как все средства управления наследовались различным предопределенным классам)
  3. поддержка интерфейса Add

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

35
ответ дан Sameer 22 January 2019 в 03:45
поделиться

Это также хорошо для Поблочного тестирования, можно ввести собственные классы (которые отвечают требованиям интерфейса) в класс, который зависит от него

4
ответ дан Richard 22 January 2019 в 03:45
поделиться

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

6
ответ дан whaley 22 January 2019 в 03:45
поделиться

Если я пишу новый класс Swimmer , чтобы добавить функциональность swim () и мне нужно использовать объект класса, скажем Dog , и это Класс Dog реализует интерфейс Animal , который объявляет swim () .

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

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

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

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