Почему я не могу понять интерфейсы? - PullRequest
50 голосов
/ 23 сентября 2008

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

Я говорю об интерфейсах в контексте интерфейсов против абстрактных классов.

Ответы [ 26 ]

2 голосов
/ 23 сентября 2008

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

Интерфейсы описывают функциональность, а не реализацию.

2 голосов
/ 21 октября 2012

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

1 голос
/ 07 июля 2014

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

1 голос
/ 23 сентября 2008

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

1 голос
/ 06 августа 2012

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

  1. Члены производного класса могут использовать открытые или защищенные члены базового класса как свои собственные.
  2. Члены производного класса могут использоваться кодом, который ожидает члена базового класса (то есть они могут быть заменяемыми).

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

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

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

1 голос
/ 05 сентября 2010

У меня была та же проблема, что и у вас, и я нахожу объяснение "контракта" немного запутанным.

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

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

Другим предложением может быть переименование интерфейса в интерфейсный класс, так как интерфейс - это просто еще один вариант класса.

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

1 голос
/ 23 сентября 2008

Как уже говорили другие, интерфейсы определяют контракт (как «будут выглядеть» классы, использующие интерфейс), а абстрактные классы определяют общую функциональность.

Посмотрим, поможет ли код:

public interface IReport
{
    void RenderReport(); // This just defines the method prototype
}

public abstract class Reporter
{
    protected void DoSomething()
    {
        // This method is the same for every class that inherits from this class
    }
}

public class ReportViolators : Reporter, IReport
{
    public void RenderReport()
    {
        // Some kind of implementation specific to this class
    }
}

public class ClientApp
{
    var violatorsReport = new ReportViolators();

    // The interface method
    violatorsReport.RenderReport();

    // The abstract class method
    violatorsReport.DoSomething();
}
1 голос
/ 24 сентября 2008

Интерфейсы - это способ реализации соглашений способом, который все еще строго типизирован и полиморфен.

Хороший пример из реального мира был бы IDisposable в .NET. Класс, реализующий интерфейс IDisposable, заставляет этот класс реализовать метод Dispose (). Если класс не реализует Dispose (), вы получите ошибку компилятора при попытке сборки. Дополнительно этот кодовый шаблон:

using (DisposableClass myClass = new DisposableClass())
  {
  // code goes here
  }

Будет вызывать автоматическое выполнение myClass.Dispose () при выходе из внутреннего блока.

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

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

1 голос
/ 23 сентября 2008

Одной из веских причин использования интерфейса против абстрактного класса в Java является то, что подкласс не может расширять несколько базовых классов, но МОЖЕТ реализовывать несколько интерфейсов.

1 голос
/ 23 сентября 2008

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

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

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

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