В чем разница между абстрактным классом и интерфейсом?

Ответ

Основное концептуальное различие в том, что абстрактный класс определяет что объект есть (is-a relationship), а интерфейс определяет что объект может делать (capability).

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

  • Может содержать как абстрактные методы (без реализации), так и конкретные методы с реализацией.
  • Может иметь поля (свойства) с различными модификаторами доступа (public, protected, private).
  • Может содержать конструктор.
  • Класс может наследовать только от одного абстрактного класса.
  • Используется, когда родственные классы имеют общее состояние и поведение.

Интерфейс:

  • До Java 8 / C# 8.0 содержал только сигнатуры методов (контракт). Современные версии позволяют добавлять реализации по умолчанию (default в Java, virtual в C#) и статические методы.
  • Не может содержать поля состояния (только константы).
  • Не может иметь конструктор.
  • Класс может реализовывать множество интерфейсов.
  • Используется для определения контракта, который могут выполнять несвязанные классы.

Пример на C#:

// Абстрактный класс: общая базовая логика
abstract class DataExporter
{
    protected string _data;
    public DataExporter(string data) { _data = data; } // Конструктор
    public virtual void PrepareData() { /* общая реализация */ } // Конкретный метод
    public abstract void Export(); // Абстрактный метод
}

// Интерфейс: контракт на возможность логирования
interface ILoggable
{
    void Log(string message); // Только сигнатура
}

// Класс использует и наследование, и реализацию интерфейса
class CsvExporter : DataExporter, ILoggable
{
    public CsvExporter(string data) : base(data) { }
    public override void Export() { /* экспорт в CSV */ }
    public void Log(string message) { /* логирование */ }
}

Ответ 18+ 🔞

А, ну это классика, ёпта! Вечная тема, про которую на собесах спрашивают, чтобы проверить, не идиот ли ты. Сейчас разжую, как есть, без соплей.

Представь, что ты проектируешь армию роботов. Вот смотри.

Абстрактный класс — это как чертёж конкретного вида робота. Допустим, «БоевойАндроидМодельТ800». Он уже есть что-то. У него есть стальной каркас (поле _skeleton), встроенный аккумулятор (поле _battery). У него есть общий для всех Т800 метод ЗагрузитьПатроны() — это конкретная реализация, все делают это одинаково. И есть абстрактный метод ВыбратьЦель(), потому что логика выбора у снайпера и у штурмовика разная. Но главное — каждый новый робот НАСЛЕДУЕТ эту общую сущность. Он является (is-a) Т800. Больше чем от одного чертежа унаследовать нельзя, иначе получится манда с ушами, а не робот.

Интерфейс — это не «что он есть», а «что он умеет делать». Это набор скиллов, которые можно навесить на кого угодно. Интерфейс IЛетающий — контракт: «у того, кто меня реализует, будет метод Взлететь()». И его может реализовать и наш Т800 (если прикрутить реактивный ранец), и птица, и самолёт, и твой сосед после десятой рюмки. Класс может взять овердохуища таких интерфейсов: IСтреляющий, IПлавающий, IГоворящийГолосомАрнольда. В старых языках это был просто список методов «сделай хоть как, но сделай». Сейчас туда можно и готовую default-реализацию запихнуть, типа стандартного «взлететь по-чайничьи».

Короче, суть:

  • Абстрактный класс — это «КТО ТЫ» (родитель, общая база с данными и логикой). Наследование — штука серьёзная, доверия ебать ноль, поэтому только от одного.
  • Интерфейс — это «ЧЕМ ТЫ ЕЩЁ УМЕЕШЬ» (роль, умение). Их можно нацепить много, как значки на рюкзак.

Вот тебе живой пример на C#, чтоб вообще ни хуя себе не осталось:

// Абстрактный класс: он определяет сущность "Писатель"
abstract class Writer
{
    protected string _name; // Поле, состояние. У каждого писателя есть имя.
    public Writer(string name) { _name = name; } // Конструктор есть!
    public void MakeCoffee() { Console.WriteLine("Варит кофе. Без него никуда."); } // Конкретный метод, общий для всех
    public abstract void Write(); // Абстрактный метод. КАК писать — каждый решает сам.
}

// Интерфейс: умение "Сводить с ума редактора"
interface IDriveEditorCrazy
{
    void MissDeadline(); // Просто контракт. Обязуешься иметь метод "просрочить дедлайн".
}

// Наш класс. Он ЕСТЬ Писатель (наследует), и он УМЕЕТ сводить с ума редактора (реализует интерфейс).
class FantasyWriter : Writer, IDriveEditorCrazy
{
    public FantasyWriter(string name) : base(name) { }

    public override void Write() 
    { 
        Console.WriteLine($"Пишет про эльфов и драконов. {_name} в ударе!");
    }

    public void MissDeadline() // Реализация интерфейса
    {
        Console.WriteLine("'Добавлю ещё одну сюжетную арку', — говорит он за день до сдачи.");
    }
}

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

Видео-ответы