Реализации интерфейса по умолчанию. В чем сейчас глубокая значимая разница между абстрактным классом и интерфейсом?

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

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

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

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

НОНОНО

Я заметил, что у нас будут методы интерфейса по умолчанию в C# 8.0

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

Я знаю, что мы не можем сделать состояние в интерфейсе, будет ли это только одно различие между ними?

3 ответа

Решение

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

еще пара хороших моментов, упомянутых в этом посте:

  • Эта функция позволяет C# взаимодействовать с API-интерфейсами, ориентированными на Android (Java) и iOs (Swift), которые поддерживают аналогичные функции.
  • Как оказалось, добавление реализаций интерфейса по умолчанию обеспечивает элементы языковой особенности "черты" ( https://en.wikipedia.org/wiki/Trait_(computer_programming)). Черты оказались мощным методом программирования ( http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf).

Концептуальный

Прежде всего, существует концептуальная разница между классом и интерфейсом.

  • Класс должен описывать отношения "есть". Например, Феррари - это машина.
  • Интерфейс должен описывать контракт типа. Например, у автомобиля есть рулевое колесо.

В настоящее время абстрактные классы иногда используются для повторного использования кода, даже если нет отношения "есть". Это загрязняет объектно-ориентированный дизайн. НапримерFerrariClass наследуется от CarWithSteeringWheel

Преимущества

  • Итак, сверху вы можете повторно использовать код, не вводя (концептуально неверный) абстрактный класс.
  • Вы можете наследовать от нескольких интерфейсов, в то время как абстрактный класс - это только одно наследование
  • В C# существует ко- и контравариантность интерфейсов, а не классов.
  • Реализовать интерфейс проще, потому что некоторые методы имеют реализации по умолчанию. Это могло бы сэкономить много времени разработчику интерфейса, но пользователь не заметит разницы:)
  • Но самое главное для меня (поскольку я сопровождаю библиотеку) вы можете добавлять новые методы в интерфейс, не внося критических изменений! До C#8, если интерфейс был опубликован публично, его нужно было исправить. Потому что изменение интерфейса может сильно поломать.

Интерфейс регистратора

Этот пример показывает некоторые из преимуществ.

Вы можете описать (упрощенный) интерфейс регистратора следующим образом:

interface ILogger
{
    void LogWarning(string message);

    void LogError(string message);

    void Log(LogLevel level, string message);
}

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

Лучшим интерфейсом со значениями по умолчанию будет:

interface ILogger
{
    void LogWarning(string message) => Log(LogLevel.Warning, message);

    void LogError(string message) => Log(LogLevel.Error, message);

    void Log(LogLevel level, string message);
}

Теперь пользователь по-прежнему может использовать все методы, но разработчику нужно только реализовать Log. Также он мог реализоватьLogWarning а также LogError.

Кроме того, в будущем вы можете добавить logLevel "Catastrophic". До C#8 вы не могли добавить методLogCatastrophic в ILogger без нарушения всех текущих реализаций.

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

А. Причины

Методы интерфейса по умолчанию не были введены для замены абстрактных классов.

Что нового в C# 8.0 гласит:

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

Эта функция также позволяет C# взаимодействовать с API-интерфейсами, предназначенными для Android или Swift, которые поддерживают аналогичные функции. Методы интерфейса по умолчанию также позволяют использовать сценарии, аналогичные языковой функции "черт".

Б. Функциональные различия

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

Вот несколько вещей, которые интерфейс по-прежнему не может иметь / делать, в то время как абстрактный класс может:

  • есть конструктор,
  • держать состояние,
  • унаследовать от не абстрактного класса,
  • есть частные методы.

C. Дизайн

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

( В каких случаях следует выбирать наследование интерфейса при разработке библиотек классов C#?)

  • Наследование описывает отношения "есть-а".
  • Реализация интерфейса описывает отношения "можно сделать".

Еще одна вещь, которая до сих пор делает интерфейс уникальным, это ковариация / контравариантность.

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

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

abstract class LivingEntity
{
    public int Health
    {
        get;
        protected set;
    }


    protected LivingEntity(int health)
    {
        this.Health = health;
    }
}

class Person : LivingEntity
{
    public Person() : base(100)
    { }
}

class Dog : LivingEntity
{
    public Dog() : base(50)
    { }
}

Два основных отличия:

  • Абстрактные классы могут иметь состояние, а интерфейсы - нет.
  • Тип может быть производным от одного абстрактного класса, но может реализовывать несколько интерфейсов.

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

Другие вопросы по тегам