Aus weniger wird exponentiell mehr
Wenn es in C ++ und Java um Typhierarchien und die Taxonomie von Typen geht, geht es in Go um die Komposition.
Aus weniger wird exponentiell mehr
Wenn es in C ++ und Java um Typhierarchien und die Taxonomie von Typen geht, geht es in Go um die Komposition.
Antworten:
Er bedeutet, dass Sie etwas in der Reihenfolge verwenden würden:
class A : public B {};
In etwas wie Java oder C ++ würden Sie in Go Folgendes verwenden:
class A {
B b;
};
Ja, dies bietet vererbungsähnliche Funktionen. Lassen Sie uns das obige Beispiel etwas erweitern:
struct B {
int foo() {}
};
struct A {
B b;
};
A a;
a.foo(); // not allowed in C++ or Java, but allowed in Go.
Dazu verwenden Sie jedoch eine Syntax, die in C ++ oder Java nicht zulässig ist. Sie lassen das eingebettete Objekt ohne einen eigenen Namen, sodass es eher wie folgt aussieht:
struct A {
B;
};
Diese Frage / Problem ist dieser ähnlich .
In Go hast du nicht wirklich OOP.
Wenn Sie ein Objekt "spezialisieren" möchten, müssen Sie es einbetten. Hierbei handelt es sich um eine Komposition, die jedoch teilweise der Vererbung ähnelt. Du machst es so:
type ConnexionMysql struct {
*sql.DB
}
In diesem Beispiel ist ConnexionMysql eine Art Spezialisierung von * sql.DB, und Sie können auf ConnexionMysql die in * sql.DB definierten Funktionen aufrufen:
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)
Auf den ersten Blick könnte man denken, dass diese Komposition das Werkzeug ist, um Ihre übliche Taxonomie zu erstellen.
Aber
Wenn eine in * sql.DB definierte Funktion andere in * sql.DB definierte Funktionen aufruft, werden die in ConnexionMysql neu definierten Funktionen auch dann nicht aufgerufen, wenn sie vorhanden sind.
Bei der klassischen Vererbung tun Sie häufig Folgendes:
func (db *sql.DB) doComplexThing() {
db.doSimpleThing()
db.doAnotherSimpleThing()
}
func (db *sql.DB) doSimpleThing() {
// standard implementation, that we expect to override
}
Das heißt, Sie definieren doComplexThing
die Superklasse als Organisation bei Aufrufen der Spezialisierungen.
In Go würde dies jedoch nicht die spezialisierte Funktion, sondern die "Superklasse" -Funktion aufrufen.
Wenn Sie also einen Algorithmus haben möchten, der einige in * sql.DB definierte, aber in ConnexionMySQL (oder anderen Spezialisierungen) neu definierte Funktionen aufrufen muss, können Sie diesen Algorithmus nicht als Funktion von * sql.DB definieren, sondern müssen ihn an anderer Stelle definieren und diese Funktion erstellt nur die Anrufe an die angegebene Spezialisierung.
Du könntest es so machen, indem du Interfaces benutzt:
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
}
Dies unterscheidet sich erheblich von der klassischen Übersteuerung von Klassenhierarchien.
Insbesondere können Sie offensichtlich nicht direkt eine dritte Ebene haben, die eine Funktionsimplementierung von der zweiten erbt.
In der Praxis beenden Sie die Verwendung der meisten (orthogonalen) Schnittstellen und lassen die Aufrufe einer bereitgestellten Implementierung durch die Funktion komponieren, anstatt dass die "Superklasse" der Implementierung diese Aufrufe organisiert.
Nach meiner Erfahrung führt dies zu einem praktischen Fehlen von Hierarchien, die tiefer als eine Ebene liegen.
Zu oft, in anderen Sprachen, haben Sie den Reflex, wenn Sie sehen, dass das Konzept A eine Spezialisierung des Konzepts B ist, diese Tatsache zu wiederholen, indem Sie eine Klasse B und eine Klasse A als Unterklasse von B erstellen Um Ihre Daten zu verarbeiten, verbringen Sie Zeit damit, die Taxonomie von Objekten in Ihrem Code nach dem Prinzip zu reproduzieren, dass dies Realität ist.
In Go können Sie keinen allgemeinen Algorithmus definieren und ihn spezialisieren. Sie müssen einen allgemeinen Algorithmus definieren und sicherstellen, dass dieser allgemein ist und mit den bereitgestellten Schnittstellenimplementierungen funktioniert.
Ich war entsetzt über die zunehmende Komplexität einiger Hierarchiebäume, auf denen die Codierer komplexe Hacks durchgeführt haben, um einen Algorithmus zu implementieren, dessen Logik schließlich alle Ebenen impliziert Sie denken, anstatt nur die Konzepte Ihres Anwendungsmodells zu überarbeiten.