Od mniej znaczy wykładniczo więcej
Jeśli C ++ i Java dotyczą hierarchii typów i taksonomii typów, Go dotyczy kompozycji.
Od mniej znaczy wykładniczo więcej
Jeśli C ++ i Java dotyczą hierarchii typów i taksonomii typów, Go dotyczy kompozycji.
Odpowiedzi:
Ma na myśli to, że w przypadku użycia czegoś w kolejności:
class A : public B {};
w czymś takim jak Java lub C ++, w Go użyłbyś (coś równoważnego):
class A {
B b;
};
Tak, zapewnia to funkcje podobne do dziedziczenia. Rozwińmy trochę powyższy przykład:
struct B {
int foo() {}
};
struct A {
B b;
};
A a;
a.foo(); // not allowed in C++ or Java, but allowed in Go.
Aby to zrobić, używasz składni, która jest niedozwolona w C ++ lub Javie - pozostawiasz osadzony obiekt bez własnej nazwy, więc bardziej przypomina:
struct A {
B;
};
To pytanie / problem jest trochę podobne do tego .
W Go tak naprawdę nie masz OOP.
Jeśli chcesz „specjalizować” obiekt, robisz to przez osadzenie, które jest kompozycją, ale z pewnymi dodatkami, które częściowo przypominają dziedziczenie. Robisz to w ten sposób:
type ConnexionMysql struct {
*sql.DB
}
W tym przykładzie ConnexionMysql jest rodzajem specjalizacji * sql.DB i można wywołać w ConnexionMysql funkcje zdefiniowane w * 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)
Na pierwszy rzut oka możesz więc pomyśleć, że ta kompozycja jest narzędziem do stworzenia zwykłej taksonomii.
Ale
jeśli funkcja zdefiniowana w * sql.DB wywołuje inne funkcje zdefiniowane w * sql.DB, nie wywoła funkcji przedefiniowanych w ConnexionMysql, nawet jeśli one istnieją.
W przypadku dziedziczenia klasycznego często robisz coś takiego:
func (db *sql.DB) doComplexThing() {
db.doSimpleThing()
db.doAnotherSimpleThing()
}
func (db *sql.DB) doSimpleThing() {
// standard implementation, that we expect to override
}
Oznacza to, że definiujesz doComplexThing
w superklasie jako organizację na wezwanie specjalizacji.
Ale w Go nie wywołałoby to funkcji specjalistycznej, ale funkcję „nadklasy”.
Jeśli więc chcesz mieć algorytm, który musi wywoływać niektóre funkcje zdefiniowane w * sql.DB, ale przedefiniowane w ConnexionMySQL (lub innych specjalizacjach), nie możesz zdefiniować tego algorytmu jako funkcji * sql.DB, ale musisz go zdefiniować gdzie indziej a ta funkcja będzie składać tylko połączenia z podaną specjalizacją.
Możesz to zrobić za pomocą interfejsów:
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
}
Jest to całkiem odmienne od klasycznego przesłonięcia hierarchii klas.
W szczególności, oczywiście nie możesz bezpośrednio mieć trzeciego poziomu dziedziczącego implementację funkcji od drugiego.
W praktyce przestaniesz używać głównie (ortogonalnych) interfejsów i pozwolisz, aby funkcja tworzyła wywołania na dostarczonej implementacji zamiast organizować te wywołania przez „nadklasę” implementacji.
Z mojego doświadczenia wynika, że prowadzi to do praktycznego braku hierarchii głębszych niż jeden poziom.
Zbyt często w innych językach masz odruch, gdy widzisz, że pojęcie A jest specjalizacją pojęcia B, aby to potwierdzić, tworząc klasę B i klasę A jako podklasę B. Zamiast tworzyć programując wokół danych, spędzasz czas na odtwarzaniu taksonomii obiektów w kodzie, na zasadzie, że jest to rzeczywistość.
W Go nie można zdefiniować ogólnego algorytmu i go specjalizować. Musisz zdefiniować ogólny algorytm i upewnić się, że jest on ogólny i działa z dostarczonymi implementacjami interfejsu.
Będąc przerażonym rosnącą złożonością niektórych drzew hierarchicznych, na których koderzy robili skomplikowane włamania, aby dostosować się do algorytmu, którego logika w końcu implikuje wszystkie poziomy, powiedziałbym, że jestem zadowolony z prostszej logiki Go, nawet jeśli wymusza zamiast myśleć o koncepcjach modelu aplikacji, musisz pomyśleć.