Абстрактные классы vs Интерфейсы

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

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

Ответ 1

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

Ответ 2

Эта статья CodeProject содержит много информации о различии между ними, включая таблицу, сравнивающую и сравнивающую функции каждого из них.

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

Ответ 3

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

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

Ответ 4

Для вашего первого вопроса, да.

Для вашего второго ответа я дам вам несколько советов, которые я использовал.

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

Использовать абстрактный класс

  • При создании библиотеки классов, которая будет широко распространена или повторно использована, особенно для клиентов, используйте абстрактный класс, предпочитая интерфейс; потому что это упрощает управление версиями.

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

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

  • Подкласс - это только базовый класс в иерархии, к которой этот класс логически принадлежит.

Использовать интерфейс

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

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

  • Используйте интерфейс для создания полиморфной иерархии для типов значений.

  • Используйте интерфейс, когда действительно нужен непреложный контракт.

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

Ответ 5

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

Ответ 6

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

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

public interface IFoo
{
    void Bar();
}

public abstract class FooBase : IFoo
{
    public abstract void Bar()
    {
        // Do some stuff usually required for IFoo.
    }
}

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

public class FooOne : FooBase
{
    public override void Bar()
    {
        base.Bar(); // Use base implementation.

        // Do specialized stuff.
    }
}

public class FooTwo : FooBase
{
    public override void Bar()
    {
        // Do other specialized stuff.

        base.Bar(); // Use base implementation.

        // Do more specialized stuff.
    }
}

// This class cannot use the base implementation from FooBase because
// of inheriting from OtherClass but it can still implement IFoo.
public class FooThree : OtherClass, IFoo
{
    public virtual void Bar()
    {
        // Do stuff.
    }
}

Ответ 7

Если у вас нет стандартного/общего кода, перейдите с интерфейсом.

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

public abstract class Processor
{
  // this is the only public method
  // implements the order of the separate steps
  public void Process()
  {
    Step1();
    Step2();
    //... 
  }
  // implementation is provided by derived classes
  protected abstract void Step1();
  protected abstract void Step2();
}

Ответ 8

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

Интерфейсы могут использоваться для полиморфизма в самом общем смысле. Например, ICollection используется для определения интерфейса для всех коллекций (их довольно много). Здесь он определяет операции, которые вы хотите выполнить для определенного типа. Существует много других применений (таких как тестируемость, зависимость и т.д.). Кроме того, интерфейсы могут быть смешаны, и это работает как концептуально, так и технически.

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

Ответ 9

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

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

Это намечено в нескольких ответах, но не указано явно.

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

Не считайте интерфейсы частью иерархии объектов. Они обычно являются лишь небольшими частями функциональности (или, по крайней мере, конкретными, если не маленькими), что ваша настоящая иерархия объектов может объявлять как реализующая. Возьмите IDisposable, например. Если бы вы писали это, спросите себя, должен ли он быть абстрактным классом или интерфейсом? Кажется очевидным, что в этом случае это две совершенно разные вещи. Я хочу быть одноразовым. Подумайте о ICloneable и IEnumerable. Вы можете реализовать их в своем классе, не пытаясь сделать свой класс из некоторых несвязанных классов, таких как List или Array. Или возьмите IEnumerator. Просто предоставляет тип MoveNext для объекта. Мой класс может обеспечить эту функциональность без необходимости неуклюже быть получена из некоторого другого типа данных последовательного сбора, который не имеет ничего общего с моим классом.

Ответ 13

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

Ответ 14

Вы всегда должны отдавать предпочтение программированию интерфейсам, чем конкретным классам.

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

Ответ 15

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

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

Использование:

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