На этом шаге рассмотрим ключевые понятия ООП в Go.
Важнейшим отличием поддержки объектно-ориентированного программирования на языке Go от аналогичной поддержки в таких языках, как C++, Java и Python, является отсутствие механизма наследования.
Вместо механизмов агрегирования и наследования, как в большинстве других объектно-ориентированных языков, Go поддерживает механизмы агрегирования (также называется композицией) и встраивания. Чтобы понять разницу между агрегированием и встраиванием, рассмотрим короткий фрагмент.
type ColoredPoint struct { color.Color // Анонимное (безымянное) поле (встраивание), //это имя типа из пакета image/color x, y int // Именованные поля (агрегирование), //это имена полей типа int }
В терминологии языка Go color.Color, x и y являются полями структуры ColoredPoint. Поле color.Color является анонимным (поскольку не имеет имени) и поэтому считается встроенным полем. Поля x и y – это именованные агрегированные поля. Если создать значение типа ColoredPoint (например, так: point := ColoredPoint{}), его поля будут доступны как point.Color, point.x и point.y.
Термины "класс", "объект" и "экземпляр", устоявшиеся в объектно-ориентированном программировании с поддержкой наследования, в языке Go вообще не используются. Вместо них используются термины "тип" и "значение" , где значения пользовательских типов могут иметь методы.
В отсутствие наследования исчезли и виртуальные функции . Вместо этого механизма Go предлагает механизм динамической типизации. В языке Go параметры могут определяться как конкретные типы (такие как int, string) или как интерфейсы, то есть значения, обладающие методами, которые определяются интерфейсами. В параметре, объявленном как интерфейс, можно передать любое значение, при условии что оно обладает методами этого интерфейса. Это обеспечивает гибкость и возможности, особенно в соединении с поддержкой методов доступа встроенных значений в языке Go.
Одно из преимуществ механизма наследования состоит в том, что некоторые методы достаточно реализовать только один раз в базовом классе, и затем их можно использовать во всех его подклассах. То же самое в языке Go достигается двумя способами.
Первый заключается в использовании механизма встраивания. При встраивании типов методы достаточно создать только один раз, во встраиваемом типе, и использовать их во всех других типа, включающих встраиваемый.
Второй состоит в том, чтобы в каждом типе реализовать свои версии методов в виде тонких оберток (как правило, однострочных), которые просто передают работу единственной функции.
На следующем шаге продолжим рассматривать понятия объектно-ориентированного программирования в Go.