Вопрос на собеседовании обычно звучит так: расскажи про ООП в Go
Рассказываю:
Go реализует парадигмы ООП немного иначе, чем классические ООП языки. Разберём каждый принцип на простых примерах из жизни и на примерах кода на Go.
Инкапсуляция
(мой любимый пример) Представьте наручные часы. У часов есть стрелки, циферблат и, возможно, дата. Мы можем взять их, посмотреть время или установить будильник. Внутри часов скрыто множество сложных механизмов и деталей, которые обеспечивают правильную работу часов.
Эти механизмы и детали инкапсулированы внутри корпуса часов. Мы не знаем, как они работают, и нам это, в общем-то, и не нужно. Главное, что часы показывают правильное время. Все сложности и детали работы часов скрыты от нас, а мы взаимодействуем только с предоставляемым интерфейсом - стрелками, кнопками.
Как инкапсуляция релизуется в Go: Мы создаем структуры, которые скрывают внутренние детали и механизмы, предоставляя пользователю только необходимый и безопасный интерфейс для взаимодействия. Это позволяет изолировать сложную логику и упростить использование объекта.
В этом примере мы не раскрываем, как именно часы отслеживают время, например, как они учитывают переход через полночь и так далее. Мы просто предоставляем методы для получения и установки времени — GetTime и SetTime.
Go обеспечивает инкапсуляцию на уровне пакета. Единственный механизм управления видимостью — использование прописных и строчных букв.
Идентификаторы с прописной (заглавной) буквы экспортируются. В нашем примере структура Watch и ее методы GetTime и SetTime — экспортируется, то есть доступы за пределами пакета.
Идентификаторы со строчной (маленькой) буквы не экспортируются. В нашем примере поля структуры Watch: hours и minutes будут доступны только из того же пакета, за пределами к ним обратиться и вызвать их нельзя.
Наследование Композиция
Тут все просто. На реальном примере можно объяснить так, у нас есть рецепт торта. Мы можем создать новые рецепты на основе этого базового рецепта, добавляя новые ингредиенты или меняя способ приготовления.
Как наследование реализуется в Go: в классическом виде никак, то есть мы не можем наследовать один объект от другого. Вместо наследования используют композицию — разделение крупных структур на более мелкие для их последующего объединения. Базовая структура встраивается в дочернюю, после чего базовые поля и методы напрямую доступы дочерней структуре.
Композиция определяет класс как сумму его частей, в то время как при наследовании мы получаем один класс из другого. Классы и объекты, созданные с использованием наследования, тесно связаны, и изменение родителя может сломать код. Структуры, созданные с помощью композиции, слабо связаны, можно легко изменять составные части, не нарушая код.
Переходим к примеру на Go:
Мы встроили в дочернюю структуру ChocolateCake базовую Cake и теперь у нее есть доступ к ингредиентам для торта от базовой структуру, а также к своим экстра-ингредиентам.
Полиморфизм
В жизни эту парадигму можно представить так, есть несколько разных музыкальных инструментов: гитара, флейта и барабан. Каждый из этих инструментов производит звук, но делает это по-разному. Тем не менее, если позвать группу музыкантов, и попросить их "сыграть" на своем инструменте, каждый бы знал, что делать, несмотря на различия в этих инструментах.
Как полиморфизм реализуется в Go: через интерфейсы. Мы можем определить интерфейс с набором методов и затем реализовать этот интерфейс разными структурами.
Предположим, у нас есть интерфейс Instrument с методом Play():
Создадим несколько структур, каждая из которых реализует этот интерфейс:
Теперь, благодаря полиморфизму, мы можем создать функцию, которая принимает интерфейс Instrument и вызывает метод Play, не заботясь о том, какой конкретный тип инструмента передан. Мы можем передать любой объект, реализующий интерфейс Instrument, в функцию PlayInstrument:
Полиморфизм позволяет нам абстрагироваться от конкретных типов и работать с различными объектами, используя один и тот же интерфейс. Это упрощает код, делает его более гибким и повышает его переиспользуемость.
Нам этом все. Возможно, слишком подробно, но с реальными примерами все эти концепции прочнее осядут в памяти.