Как решить между интерфейсом или базовым классом для новой реализации?

237
23

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


Примеры того, как и почему были бы очень благодарны.

спросил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
1
Решение
269

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


Пример:


class Person
{
string Name { get; set; }
}

class Employee : Person
{
string Company { get; set; }
}


Для Employee имеет смысл наследовать от Person, потому что класс Employee не должен определять свойство Name, поскольку он разделяет реализацию.


interface IPolygon
{
double CalculateArea()
}

class Rectangle : IPolygon
{
double Width { get; set; }
double Height { get; set; }

double CalculateArea()
{
return this.Width * this.Height;
}
}

class Triangle : IPolygon
{
double Base { get; set; }
double Height { get; set; }

double CalculateArea()
{
return 0.5 * this.Base * this.Height;
}
}

Поскольку Rectangle и Triangle имеют такие разные реализации CalculateArea, им не имеет смысла наследовать их из базового класса.


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


И, как указано в j__m, вы не можете наследовать от нескольких базовых классов, но вы можете реализовать несколько интерфейсов.


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

ответил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
170

Чтобы решить, использовать ли абстрактный класс или интерфейс, я считаю эту статью очень полезной Источник:


Хороший способ отличить случай для того или другого для меня всегда был следующим:

    Есть ли много классов, которые могут быть "сгруппированы вместе" и описаны одним существительным ? Если это так, иметь абстрактный класс по имени этого существительного и наследовать от него классы. (Ключевым решателем является то, что эти классы имеют общие функциональные возможности, и вы никогда не создадите экземпляр только Animal... вы всегда создавали бы определенный тип Animal: реализация вашего Основной основной класs > Пример: Cat и Собака могут наследовать от абстрактного класса Animal, и этот абстрактный базовый класс реализует метод void Breathe(), которые все животные будут делать таким же образом. (Я мог бы сделать этот метод виртуальным, чтобы я мог переопределить его для определенных животных, таких как Рыба, которые не дышат так же, как большинство животных).

    Какие типы глаголов могут применяться к моему классу, которые в целом могут быть применены и к другим? Создайте интерфейс для каждого из этих глаголов. Пример: все животные могут быть поданы, поэтому я создам интерфейс под названием IFeedable и реализую Animal. Только Dog и Лошадь достаточно хороши, хотя для реализации ILikeable - я не буду реализовывать это в базовом классе, так как это не относится к Cat.

Также обратите внимание на этот интерфейс против базового класса.

ответил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
99

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


Интерфейс не позволяет вам определять контракты конструктора.


В приведенном ниже примере каждый объект Animal должен иметь ИМЯ. Это невозможно выполнить с помощью интерфейса.


public abstract class Animal
{
public Animal(string name)
{
this.Name = name;
}

public string Name
{
get;
private set;
}
}

public class Cat : Animal
{
public Cat(string name)
: base(name)
{

}

string NoOfLegs { get; set; }
}

class Program
{
static void Main(string[] args)
{
Animal aCat = new Cat("a");
}
}

ответил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
77

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



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



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

ответил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
77

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


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

ответил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
63

Я нашел здесь аналогию:


Абстрактный базовый класс: -
Производитель автомобилей может разработать бензиновый двигатель, который имеет несколько вариантов (1,6, 2 л и т.д.). Литье блоков двигателя можно рассматривать как абстрактный базовый класс, т.е. Определяет основную форму и особенности движка. Версия 2L может иметь большую головку цилиндра и т.д.


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

ответил(а) 2021-01-25T16:25:36+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема