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

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

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

Интерфейс:

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

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

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

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

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

См. Также :

Ответы [ 34 ]

25 голосов
/ 23 января 2012

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

1- Абстрактный (или чисто абстрактный) класс предназначен для реализации иерархии. Если ваши бизнес-объекты выглядят несколько структурно схожими, представляя только родительско-дочерние (иерархические) отношения, то будут использоваться классы наследования / абстрактные. Если ваша бизнес-модель не имеет иерархии, тогда не следует использовать наследование (здесь я не говорю о логике программирования, например, некоторые шаблоны проектирования требуют наследования). Концептуально абстрактный класс - это метод реализации иерархии бизнес-модели в ООП, он не имеет ничего общего с интерфейсами, фактически сравнивать абстрактный класс с интерфейсом бессмысленно, поскольку оба концептуально являются совершенно разными вещами, в интервью его просят просто проверить Концепции, потому что они выглядят так, предоставляют несколько одинаковую функциональность, когда речь идет о реализации, и мы, программисты, обычно уделяем больше внимания кодированию. [Помните также, что абстракция отличается от абстрактного класса].

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

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

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

Я полагаю, что оба интервьюера ожидали однозначного различия между этими двумя, а когда вы потерпели неудачу, они пытались подтолкнуть вас к этой разнице, внедрив ONE в качестве ДРУГОГО

Что если бы у вас был класс Abstract только с абстрактными методами?

21 голосов
/ 17 апреля 2009

для .Net,

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

РЕДАКТИРОВАТЬ: С другой стороны, я бы даже не использовал фразу «подкласс» (или фразу «наследование») для описания классов, «определенных для реализации» интерфейса. Для меня интерфейс - это определение контракта, которому должен соответствовать класс, если он был определен для «реализации» этого интерфейса. Он ничего не наследует ... Вы должны сами все добавить, явно.

17 голосов
/ 05 декабря 2014

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

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

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

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

16 голосов
/ 14 августа 2014

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

Плюсы:

  1. Позволяет множественное наследование
  2. Обеспечивает абстракцию, не раскрывая, какой именно тип объекта используется в контексте
  3. обеспечивает согласованность путем конкретной подписи контракта

Минусы:

  1. Необходимо выполнить все контракты, определенные
  2. Не может иметь переменных или делегатов
  3. Однажды определенное не может быть изменено без нарушения всех классов

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

Плюсы:

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

Минусы:

  1. Не может быть создан
  2. Не поддерживает множественное наследование
13 голосов
/ 20 августа 2013
After all that, the interviewer came up with the question "What if you had an 
Abstract class with only abstract methods? How would that be different
from an interface?" 

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

An another interviewer asked me what if you had a Public variable inside
the interface, how would that be different than in Abstract Class?

Переменные в интерфейсах по умолчанию являются общедоступными static и final. Вопрос может быть сформулирован так, как если бы все переменные в абстрактном классе были публичными? Ну, они все еще могут быть не статичными и не финальными в отличие от переменных в интерфейсах.

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

12 голосов
/ 23 октября 2011
  1. Интерфейс:
    • Мы не реализуем (или не определяем) методы, мы делаем это в производных классах.
    • Мы не объявляем переменные-члены в интерфейсах.
    • Интерфейсы выражают связь HAS-A. Это означает, что они являются маской объектов.
  2. Абстрактный класс:
    • Мы можем объявлять и определять методы в абстрактном классе.
    • Мы скрываем конструкторы этого. Это означает, что нет объекта, созданного из него напрямую.
    • Абстрактный класс может содержать переменные-члены.
    • Производные классы наследуются от абстрактного класса, то есть объекты из производных классов не маскируются, а наследуются от абстрактного класса. Отношения в этом случае IS-A.

Это мое мнение.

12 голосов
/ 21 апреля 2014

Скопировано из CLR через C # Джеффри Рихтером ...

Я часто слышу вопрос: «Должен ли я разработать базовый тип или интерфейс?» Ответ не всегда ясен.

Вот несколько рекомендаций, которые могут вам помочь:

■■ Соотношение IS-A и CAN-DO Тип может наследовать только одну реализацию. Если производный type не может требовать отношения IS-A с базовым типом, не используйте базовый тип; использовать интерфейс. Интерфейсы подразумевают связь CAN-DO. Если функциональность CAN-DO, кажется, принадлежит с различными типами объектов, используйте интерфейс. Например, тип может преобразовывать экземпляры самого себя к другому типу (IConvertible) тип может сериализовать свой экземпляр (ISerializable), и т.д. Обратите внимание, что типы значений должны быть производными от System.ValueType, и, следовательно, они не могут быть производным от произвольного базового класса. В этом случае вы должны использовать отношения CAN-DO и определите интерфейс.

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

■■ Последовательная реализация Независимо от того, насколько хорошо задокументирован контракт интерфейса, он Маловероятно, что каждый будет выполнять контракт на 100 процентов правильно. На самом деле, COM страдает от этой самой проблемы, поэтому некоторые COM-объекты работают правильно только с Microsoft Word или с помощью Windows Internet Explorer. Предоставляя базовый тип с хорошим реализация по умолчанию, вы начинаете с использования типа, который работает и хорошо протестирован; Вы можете тогда модифицировать детали, требующие модификации.

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

10 голосов
/ 08 апреля 2014

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

Интерфейс является соглашением . В нем указано: «так мы будем разговаривать друг с другом». Он не может иметь никакой реализации, потому что не должен иметь какую-либо реализацию. Это контракт. Это как заголовочные файлы .h в C.

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

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

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

10 голосов
/ 05 октября 2013

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

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

C # также учитывает наследование интерфейса.

10 голосов
/ 13 ноября 2014

Поскольку вы, возможно, получили теоретические знания от экспертов, я не трачу много слов на повторение всех этих здесь, а позвольте мне объяснить на простом примере, где мы можем использовать / не можем использовать Interface и Abstract class.

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

Нижеследующий класс выступает в качестве базового класса для всех автомобилей:

public class Cars
{
    public string DigitalFuelMeter()
    {
        return "I have DigitalFuelMeter";
    }

    public string AirCondition()
    {
        return "I have AC";
    }

    public string SeatAdjust()
    {
        return "I can Adjust seat";
    }
}

Предположим, у нас есть отдельный класс для каждой машины.

public class Alto : Cars
{
    // Have all the features of Car class    
}

public class Verna : Cars
{
    // Have all the features of Car class + Car need to inherit ABS as the Braking technology feature which is not in Cars        
}

public class Cruze : Cars
{
    // Have all the features of Car class + Car need to inherit EBD as the Braking technology feature which is not in Cars        
}

Предположим, нам нужен метод наследования технологии торможения для автомобилей Verna и Cruze (неприменимо для Alto). Хотя оба используют технологию торможения, «технология» отличается. Итак, мы создаем абстрактный класс, в котором метод будет объявлен как Abstract, и он должен быть реализован в его дочерних классах.

public abstract class Brake
{
    public abstract string GetBrakeTechnology();
}

Теперь мы пытаемся унаследовать от этого абстрактного класса, и тип системы торможения реализован в Verna и Cruze:

public class Verna : Cars,Brake
{
    public override string GetBrakeTechnology()
    {
        return "I use ABS system for braking";
    }       
}

public class Cruze : Cars,Brake
{
    public override string GetBrakeTechnology()
    {
       return "I use EBD system for braking";
    }         
}

Видите проблему в двух вышеупомянутых классах? Они наследуются от нескольких классов, которые C # .Net не позволяет, хотя метод реализован в дочерних элементах. Здесь приходит необходимость интерфейса.

interface IBrakeTechnology
{
    string GetBrakeTechnology();
}

А реализация приведена ниже:

public class Verna : Cars, IBrakeTechnology
{
    public string GetBrakeTechnology()
    {
        return "I use ABS system for braking";
    }
}

public class Cruze : Cars, IBrakeTechnology
{
   public string GetBrakeTechnology()
   {
       return "I use EBD system for braking";
   }        
}

Теперь Verna и Cruze могут добиться множественного наследования с помощью собственных технологий торможения с помощью интерфейса.

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