От меньшего - экспоненциально больше
Если в C ++ и Java речь идет об иерархиях типов и таксономии типов, то в Go речь идет о композиции.
От меньшего - экспоненциально больше
Если в C ++ и Java речь идет об иерархиях типов и таксономии типов, то в Go речь идет о композиции.
Он имеет в виду, что где бы вы использовали что-то порядка:
class A : public B {};
в чем-то вроде Java или C ++, в Go вы бы использовали (что-то эквивалентное):
class A {
B b;
};
Да, это обеспечивает наследственные возможности. Давайте немного расширим пример выше:
struct B {
int foo() {}
};
struct A {
B b;
};
A a;
a.foo(); // not allowed in C++ or Java, but allowed in Go.
Однако для этого вы используете синтаксис, который не разрешен в C ++ или Java - вы оставляете внедренный объект без собственного имени, так что это больше похоже на:
struct A {
B;
};
Этот вопрос / проблема отчасти похож на этот .
В Go у вас нет ООП.
Если вы хотите «специализировать» объект, вы делаете это путем встраивания, которое является композицией, но с некоторыми вкусностями, делающими его частично похожим на наследование. Вы делаете это так:
В этом примере ConnexionMysql является разновидностью * sql.DB, и вы можете вызвать ConnexionMysql функции, определенные в * sql.DB:
Так что на первый взгляд вы можете подумать, что эта композиция - инструмент для создания вашей обычной таксономии.
Но
если функция, определенная в * sql.DB, вызывает другие функции, определенные в * sql.DB, она не будет вызывать функции, переопределенные в ConnexionMysql, даже если они существуют.
С классическим наследованием вы часто делаете что-то вроде этого:
То есть вы определяете
doComplexThing
суперкласс как организацию по вызовам специализаций.Но в Go это вызвало бы не специализированную функцию, а функцию «суперкласса».
Итак, если вы хотите иметь алгоритм, требующий вызова некоторых функций, определенных в * sql.DB, но переопределенных в ConnexionMySQL (или других специализациях), вы не можете определить этот алгоритм как функцию * sql.DB, но должны определить его в другом месте. и эта функция будет только составлять вызовы к предоставленной специализации.
Вы можете сделать это, используя интерфейсы:
Это сильно отличается от классического переопределения иерархии классов.
В частности, вы, очевидно, не можете напрямую иметь третий уровень, наследующий реализацию функции от второго.
На практике вы прекратите использовать в основном (ортогональные) интерфейсы и позволите функции составлять вызовы для предоставленной реализации вместо того, чтобы иметь "суперкласс" реализации, организующий эти вызовы.
По моему опыту, это приводит к практическому отсутствию иерархий глубже одного уровня.
Слишком часто в других языках у вас возникает рефлекс, когда вы видите, что концепция A является специализацией концепции B, чтобы утвердить этот факт путем создания класса B и класса A в качестве подкласса B. Вместо создания вашего Программируя ваши данные, вы тратите время на воспроизведение таксономии объектов в вашем коде, исходя из того, что это реальность.
В Go вы не можете определить общий алгоритм и специализировать его. Вы должны определить общий алгоритм и убедиться, что он общий и работает с предоставленными реализациями интерфейса.
Будучи напуган растущей сложностью некоторых иерархических деревьев, на которых кодеры делали сложные взломы, пытаясь приспособить алгоритм, логика которого в конечном итоге подразумевает все уровни, я бы сказал, что я доволен более простой логикой Go, даже если она вызывает вам думать, а не просто переосмысливать концепции модели вашего приложения.
источник