Від меншого - це експоненціально більше
Якщо 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, у вас насправді немає OOP.
Якщо ви хочете "спеціалізувати" об'єкт, ви робите це шляхом вбудовування, що є композицією, але з деякими смакотами, що роблять його частково схожим на спадщину. Ви робите це так:
type ConnexionMysql struct {
*sql.DB
}
У цьому зразку ConnexionMysql є різновидом спеціалізації * sql.DB, і ви можете зателефонувати на ConnexionMysql функції, визначені на * sql.DB:
type BaseMysql struct {
user string
password string
database string
}
func (store *BaseMysql) DB() (ConnexionMysql, error) {
db, err := sql.Open("mymysql", store.database+"/"+store.user+"/"+store.password)
return ConnexionMysql{db}, err
}
func (con ConnexionMysql) EtatBraldun(idBraldun uint) (*EtatBraldun, error) {
row := con.QueryRow("select pv, pvmax, pa, tour, dla, faim from compte where id=?", idBraldun)
// stuff
return nil, err
}
// somewhere else:
con, err := ms.bd.DB()
defer con.Close()
// ...
somethings, err = con.EtatBraldun(id)
Тож на перший погляд ви можете подумати, що ця композиція є інструментом для складання вашої звичної систематики.
Але
якщо функція, визначена на * sql.DB, викликає інші функції, визначені в * sql.DB, вона не буде викликати функції, визначені в ConnexionMysql, навіть якщо вони існують.
Маючи класичну спадщину, ви часто робите щось подібне:
func (db *sql.DB) doComplexThing() {
db.doSimpleThing()
db.doAnotherSimpleThing()
}
func (db *sql.DB) doSimpleThing() {
// standard implementation, that we expect to override
}
Тобто ви визначаєте doComplexThing
в суперкласі як організацію за викликами спеціалізацій.
Але в Go це не називатиметься спеціалізованою функцією, а функцією "суперкласу".
Отже, якщо ви хочете мати алгоритм, який потребує виклику деяких функцій, визначених у * sql.DB, але перероблених на ConnexionMySQL (або інших спеціалізаціях), ви не можете визначити цей алгоритм як функцію * sql.DB, але потрібно визначити його в іншому місці і ця функція буде складати лише виклики до наданої спеціалізації.
Ви можете зробити це так, використовуючи інтерфейси:
type interface SimpleThingDoer {
doSimpleThing()
doAnotherSimpleThing()
}
func doComplexThing(db SimpleThingDoer) {
db.doSimpleThing()
db.doAnotherSimpleThing()
}
func (db *sql.DB) doSimpleThing() {
// standard implementation, that we expect to override
}
func (db ConnexionMySQL) doSimpleThing() {
// other implemenation
}
Це сильно відрізняється від класичного переосмислення ієрархій класів.
Тим більше, ви, очевидно, не можете безпосередньо мати третій рівень, успадковуючи реалізацію функції від другого.
На практиці ви закінчите використовувати здебільшого (ортогональні) інтерфейси, а функція дозволить складати виклики за наданою реалізацією, а не "суперклас" для організації цих викликів.
На мій досвід, це призводить до практичної відсутності ієрархій глибше одного рівня.
Занадто часто в інших мовах у вас виникає рефлекс, коли ви бачите, що поняття A - це спеціалізація поняття B, щоб перетворити цей факт, створивши клас B і клас A як підклас В. Замість створення вашої Програмуючи ваші дані, ви витрачаєте час на відтворення систематики об'єктів у вашому коді за принципом, що це реальність.
У програмі Go ви не можете визначити загальний алгоритм і спеціалізуватися на ньому. Ви повинні визначити загальний алгоритм і переконатися, що він загальний і працює з наданими реалізаціями інтерфейсу.
Жахнувшись зростаючої складності деяких ієрархічних дерев, на яких кодери робили складні хаки, щоб спробувати пристосувати алгоритм, логіка якого, нарешті, передбачає всі рівні, я б сказав, що я задоволений більш простою логікою Go, навіть якщо це змушує ви думаєте замість того, щоб просто повторювати поняття вашої моделі програми.