Интерфейс против абстрактного класса (общий ОО) - PullRequest
1329 голосов
/ 17 апреля 2009

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

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

Интерфейс:

Каждый метод, объявленный в Интерфейсе, должен быть реализован в подклассе. В интерфейсе могут существовать только события, делегаты, свойства (C #) и методы. Класс может реализовывать несколько интерфейсов.

Абстрактный класс:

Только абстрактные методы должны быть реализованы подклассом. Класс Abstract может иметь нормальные методы с реализациями. Абстрактный класс также может иметь переменные класса, кроме событий, делегатов, свойств и методов. Класс может реализовать только один абстрактный класс только из-за отсутствия Multi-наследования в C #.

  1. После всего этого интервьюер задал вопрос: «Что если бы у вас был класс Abstract только с абстрактными методами? Как это отличалось бы от интерфейса?» Я не знал ответа, но я думаю, что это наследство, как упомянуто выше, верно?

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

См. Также :

Ответы [ 34 ]

1 голос
/ 07 мая 2018

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

Использование абстрактных классов в качестве исполнителя контракта и (частичного) контракта нарушает SRP. Использование абстрактного класса в качестве контракта (зависимости) накладывает ограничение на создание нескольких абстрактных классов для лучшего повторного использования.

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

public interface IOrderProcessor
{
    bool Process(string orderNumber);
}

public abstract class CustomerTypeOrderProcessor: IOrderProcessor
{
    public bool Process(string orderNumber) => IsValid(orderNumber) ? ProcessOrder(orderNumber) : false;

    protected abstract bool ProcessOrder(string orderNumber);

    protected abstract bool IsValid(string orderNumber);
}

public class DirectCustomerOrderProcessor : CustomerTypeOrderProcessor
{
    protected override bool IsValid(string orderNumber) => string.IsNullOrEmpty(orderNumber); 

    protected override bool ProcessOrder(string orderNumber) => true; 
}

public class InDirectCustomerOrderProcessor : CustomerTypeOrderProcessor
{
    protected override bool IsValid(string orderNumber) => orderNumber.StartsWith("EX");

    protected override bool ProcessOrder(string orderNumber) => true;
}

public abstract class CustomerCategoryOrderProcessor : IOrderProcessor
{
    public bool Process(string orderNumber) => ProcessOrder(GetDiscountPercentile(orderNumber), orderNumber);

    protected abstract int GetDiscountPercentile(string orderNumber);

    protected abstract bool ProcessOrder(int discount, string orderNumber);
}

public class GoldCustomer : CustomerCategoryOrderProcessor
{
    protected override int GetDiscountPercentile(string orderNumber) => 15;

    protected override bool ProcessOrder(int discount, string orderNumber) => true;

}

public class SilverCustomer : CustomerCategoryOrderProcessor
{
    protected override int GetDiscountPercentile(string orderNumber) => 10;

    protected override bool ProcessOrder(int discount, string orderNumber) => true;

}

public class OrderManager
{
    private readonly IOrderProcessor _orderProcessor;// Not CustomerTypeOrderProcessor or CustomerCategoryOrderProcessor 

    //Using abstract class here would create problem as we have two different abstract classes
    public OrderManager(IOrderProcessor orderProcessor) => _orderProcessor = orderProcessor;
}
1 голос
/ 07 апреля 2017

За исключением сравнения Abstract class с Interface, имеет смысл сравнить Abstract class с Concrete class.

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

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

0 голосов
/ 08 июня 2019

Эти ответы слишком длинные.

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

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

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

0 голосов
/ 01 августа 2018

Интерфейс:

Не содержит реализаций Интерфейс может наследоваться от нескольких интерфейсов (поддерживается множественное наследование) Участники автоматически становятся открытыми Может содержать свойства, методы, события и индексаторы

Абстрактный класс:

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

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

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