Каковы различия между интерфейсом и абстрактным классом в ООП

Ответ

Основное различие заключается в их назначении: абстрактный класс предоставляет базовую реализацию и общий каркас для наследников (отношение is-a), а интерфейс определяет контракт поведения (набор методов), который класс обязуется выполнить (отношение can-do).

Детальное сравнение

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

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

    • Определяет только сигнатуры методов, без их реализации.
    • Не может иметь состояния (полей).
    • Используется для обеспечения полиморфизма и слабой связности систем.
    • Класс может реализовывать несколько интерфейсов, приобретая различные "способности".

Когда что использовать?

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

Пример на Python

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

from abc import ABC, abstractmethod

# Интерфейс определяет "что делать" (контракт)
class Flyable(ABC):
    @abstractmethod
    def fly(self):
        pass

# Абстрактный класс определяет "кем быть" и может содержать реализацию
class Animal(ABC):
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def make_sound(self):
        pass

    def sleep(self):
        print(f"{self.name} is sleeping... Zzz")

# Класс реализует интерфейс и наследует абстрактный класс
class Bird(Animal, Flyable):
    def make_sound(self):
        print("Chirp!")

    def fly(self):
        print(f"{self.name} is flying high")

bird = Bird("Sparrow")
bird.make_sound() # Chirp!
bird.fly()        # Sparrow is flying high
bird.sleep()      # Sparrow is sleeping... Zzz

Ответ 18+ 🔞

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

Представь себе, что абстрактный класс — это как бы твой отец-алкаш, который тебе оставил в наследство. Он тебе оставил разваливающуюся избушку (это базовая реализация, методы с телом), долги в конторе (это поля, состояние) и наказ: «Сынок, иди работать, а то сдохнешь с голоду» (это абстрактный метод, который ты обязан реализовать). Ты наследник, ты — это он, только моложе и, хочется верить, умнее. Отношение is-a. Ты — такой же мудак, только в будущем.

А интерфейс — это как объявление на столбе: «Ищу работника. Должен уметь: воровать, врать и сливаться в толпу». Это просто список требований, контракт, блядь. Ни тебе инструментов не дали, ни денег авансом — только сказали, что ты должен уметь делать. И неважно, кто ты — студент, пенсионер или беглый зэк. Если подписался под этот контракт (implements), значит, будь добр, предоставь эти умения. Отношение can-do. Ты можешь это делать, даже если в остальном ты полное говно.

Короче, разница:

  • Абстрактный класс: Может и орать на тебя (реализованные методы), и требовать от тебя невозможного (абстрактные методы). У него есть своя биография, бабки в тумбочке и фотка бывшей жены (поля, состояние). Нужен, чтобы строить иерархию родственников-алкашей, у которых общие гены и проблемы.
  • Интерфейс: Это просто бумажка с требованиями. Никакой реализации, никакого состояния — только голые, блядь, сигнатуры методов, как список приказаний от начальства. Нужен, чтобы заставить делать что-то одинаковое самых разных уродов, которые друг с другом иначе и не пересеклись бы.

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

Пример на Python (где интерфейсы — это такие же абстрактные классы, но с понтами):

from abc import ABC, abstractmethod

# Интерфейс — контракт "Умею летать, ёпта"
class Flyable(ABC):
    @abstractmethod
    def fly(self):
        pass  # Ни хуя не сказано КАК летать, главное — летай!

# Абстрактный класс — батя-животное с наследством
class Animal(ABC):
    def __init__(self, name):
        self.name = name  # Вот, состояние, блядь, имя уже есть

    @abstractmethod
    def make_sound(self):
        pass  # А вот звук издавать ОБЯЗАН, но как — твои проблемы

    def sleep(self):  # А спать тебя уже научили, бесплатный бонус
        print(f"{self.name} is sleeping... Zzz")

# Наш герой: и животное (is-a), и летун (can-do)
class Bird(Animal, Flyable):
    def make_sound(self):
        print("Chirp!")  # Реализовал долг перед батей

    def fly(self):
        print(f"{self.name} is flying high")  # Выполнил контракт с работодателем

# Проверяем
bird = Bird("Sparrow")
bird.make_sound() # Chirp!
bird.fly()        # Sparrow is flying high
bird.sleep()      # Sparrow is sleeping... Zzz (спасибо, батя)

Вот и вся философия. Абстрактный класс — это про «кто ты есть», интерфейс — про «что ты умеешь». Не путай, а то получится манда с ушами, которая и не то, и не се.