Почему я хочу использовать интерфейсы?

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

Ответ 1

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

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

Тогда любой случайный человек может прийти, создать класс, который реализует этот интерфейс, создать экземпляр объекта этого класса и передать его в мой библиотечный код и ожидать его работы. Примечание. Конечно, можно строго реализовать интерфейс, игнорируя намерение интерфейса, поэтому просто реализовать интерфейс не гарантирует, что все будет работать. Глупо всегда находит путь!: -)

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

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

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

Ответ 2

Интерфейсы определяют контракты и что ключевое слово.

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

Итак, посмотрим пример. Предположим, у вас есть метод, который предоставляет функции для сортировки списка. Первая вещь.. какой список? Вам действительно все равно, какие элементы он выполняет, чтобы отсортировать список? Ваш ответ не должен быть... В .NET(например) у вас есть интерфейс IList, который определяет операции, которые список ДОЛЖЕН поддерживать, поэтому вам не нравятся фактические данные под поверхностью.

Вернемся к примеру, вы действительно не знаете класс объектов в списке... вам не все равно. Если вы можете просто сравнить объект, который вы могли бы также отсортировать. Таким образом, вы объявляете договор:

interface IComparable
{
  // Return -1 if this is less than CompareWith
  // Return 0 if object are equal
  // Return 1 if CompareWith is less than this
  int Compare(object CompareWith);
}

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

IComparable comp1 = list.GetItem(i) as IComparable;

if (comp1.Compare(list.GetItem(i+1)) < 0)
  swapItem(list,i, i+1)

PS: Я знаю, что примеры немного наивны, но они являются примерами...

Ответ 3

Один типичный пример - это архитектура плагина. Разработчик A пишет основное приложение и хочет убедиться, что все плагины, написанные разработчиками B, C и D, соответствуют тому, что их приложение ожидает от них.

Ответ 4

Педали на автомобиле реализуют интерфейс. Я из США, где мы едем по правой стороне дороги. Наши рулевые колеса находятся на левой стороне автомобиля. Педали для механической коробки передач слева направо - это сцепление → тормоз → ускоритель. Когда я отправился в Ирландию, вождение было отменено. Рулевое колесо автомобилей находится справа, и они едут по левой стороне дороги... но педали, а педали... они реализовали один и тот же интерфейс... все три педали были в одном порядке... поэтому, даже если класс был другим, и сеть, в которой работает этот класс, была другой, я все еще был доволен интерфейсом педали. Моему мозгу удалось назвать мои мышцы на этом автомобиле, как и на любой другой машине.

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

Ответ 5

Самый простой способ понять интерфейсы состоит в том, что они позволяют различным объектам раскрывать ОБЩИЕ функции. Это позволяет программисту писать гораздо более простой, более короткий код, который программирует интерфейс, а затем, пока объекты реализуют этот интерфейс, он будет работать.

Пример 1: Существует множество различных поставщиков баз данных: MySQL, MSSQL, Oracle и т.д. Однако все объекты базы данных могут делать одни и те же вещи, поэтому вы найдете много интерфейсов для объектов базы данных. Если объект реализует IDBConnection, он предоставляет методы Open() и Close(). Поэтому, если я хочу, чтобы моя программа была агностикой базы данных, я программирую интерфейс, а не конкретные поставщики.

IDbConnection connection = GetDatabaseConnectionFromConfig()
connection.Open()
// do stuff
connection.Close()

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

Пример 2: Если вы заметили, что почти все коллекции реализуют этот интерфейс, называемый IEnumerable. IEnumerable возвращает IEnumerator, который имеет MoveNext(), Current и Reset(). Это позволяет С# легко перемещаться по вашей коллекции. Причина, по которой он может это сделать, заключается в том, что он предоставляет интерфейс IEnumerable, который ЗНАЕТ, что объект предоставляет методы, необходимые для его прохождения. Это делает две вещи. 1) петли foreach теперь будут знать, как перечислить коллекцию, и 2) теперь вы можете применить мощные выражения LINQ к своей коллекции. Опять же, почему интерфейсы настолько полезны здесь, потому что все коллекции имеют что-то в COMMON, их можно перемещать. Каждая коллекция может перемещаться по-другому (связанный список против массива), но красота интерфейсов заключается в том, что реализация скрыта и не имеет отношения к потребителю интерфейса. MoveNext() дает вам следующий элемент в коллекции, это не имеет значения, КАК он это делает. Довольно приятно, да?

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

И, конечно, я должен дать свой любимый полиморфный пример С++, пример животных. Все животные имеют определенные характеристики. Допустим, они могут двигаться, говорить, и все они имеют имя. Поскольку я только что определил, что общего у всех моих животных, и я могу абстрагировать эти качества в интерфейсе IAnimal. Затем я создаю объект Bear, объект Owl и объект Snake, реализующий этот интерфейс. Причина, по которой вы можете хранить разные объекты вместе, реализующие один и тот же интерфейс, состоит в том, что интерфейсы представляют собой повторную передачу IS-A. Медведь IS-A животное, сова IS-A животное, поэтому он делает с тех пор, что я могу собрать их всех как Животных.

var animals = new IAnimal[] = {new Bear(), new Owl(), new Snake()} // here I can collect different objects in a single collection because they inherit from the same interface

foreach (IAnimal animal in animals) 
{
    Console.WriteLine(animal.Name)
    animal.Speak() // a bear growls, a owl hoots, and a snake hisses
    animal.Move() // bear runs, owl flys, snake slithers
}

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

Итак, самое главное с интерфейсами - это то, что имеют общие объекты, чтобы вы могли программировать против РАЗЛИЧНЫХ объектов одним и тем же способом. Экономит время, создает более гибкие приложения, скрывает сложность/реализацию, моделирует объекты/ситуации в реальном мире, среди многих других преимуществ.

Надеюсь, что это поможет.

Ответ 6

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

Классическим примером может быть IVehicle, у которого есть метод Move(). У вас могут быть классы Car, Bike и Tank, которые реализуют IVehicle. Они могут все Move(), и вы можете написать код, который не заботился о том, с каким транспортным средством он имел дело, просто чтобы он мог перемещаться().

void MoveAVehicle(IVehicle vehicle)
{
    vehicle.Move();
}

Ответ 7

Интерфейсы являются одной из форм полиморфизма. Пример:

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

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

Дескрипторы файла C в основном представляют собой интерфейс "что-то, что я могу читать и/или писать байты из и/или в", и почти каждый типизированный язык имеет такие интерфейсы, скрывающиеся в его стандартных библиотеках: потоки или что-то еще. Нетипированные языки обычно имеют неформальные типы (возможно, называемые контрактами), которые представляют потоки. Таким образом, на практике вам практически никогда не придется самостоятельно изобретать этот конкретный интерфейс: вы используете то, что дает вам язык.

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

Ответ 8

When you need different classes to share same methods you use Interfaces.

Ответ 9

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

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

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

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

Ответ 10

Представьте себе следующий базовый интерфейс, который определяет базовый механизм CRUD:

interface Storable {
    function create($data);
    function read($id);
    function update($data, $id);
    function delete($id);
}

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

Таким образом, теперь у вас может быть что-то вроде следующего:

class Logger {
    Storable storage;

    function Logger(Storable storage) {
        this.storage = storage;
    }

    function writeLogEntry() {
        this.storage.create("I am a log entry");
    }
}

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

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

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

Ответ 11

Как вы отметили, интерфейсы хороши, когда вы хотите заставить кого-то сделать его в определенном формате.

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

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

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

Ответ 12

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

Ответ 13

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

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

В общем, они уменьшают сцепление в коде. Это хорошая вещь.

Ваш код также может быть проще протестировать таким образом.

Ответ 14

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

Затем вы можете указать ICollection интерфейса с методами add(), remove() и contains().

Код, который не должен знать, какая коллекция (List, Array, Hash-table, Red-black tree и т.д.) может принимать объекты, которые реализовали интерфейс, и работать с ними, не зная их фактического типа.

Ответ 15

В .Net я создаю базовые классы и наследую их, когда классы каким-то образом связаны. Например, базовый класс Person может быть унаследован Employee и Customer. У человека могут быть общие свойства, такие как адресные поля, имя, телефон и т.д. Сотрудник может иметь свой собственный отдел. Клиент имеет другие эксклюзивные свойства.

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

Ответ 16

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

Интерфейсы могут иметь разные Цели:

  • Предоставлять различные реализации для одной и той же цели. Типичный пример это список, который может иметь разные реализации для разных (использование LinkedList, ArrayList и т.д.).
  • Разрешить изменение критериев. Например, функция сортировки может принимать Сопоставимый интерфейс для предоставлять любые критерии сортировки, основанный на том же алгоритме.
  • Скрыть детали реализации. Это также облегчает пользователю читайте комментарии, так как в теле интерфейса есть только методы, поля и комментарии, не долго куски кода для пропуска.

В статье полный текст: http://weblogs.manas.com.ar/ary/2007/11/

Ответ 17

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

Например:

public interface IExample
{
    void Foo();
}

public class Example : IExample
{
    // explicit implementation syntax
    void IExample.Foo() { ... }
}

/* Usage */
Example e = new Example();

e.Foo(); // error, Foo does not exist

((IExample)e).Foo(); // success

Ответ 20

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