2016-07-06 7 views
2

Ich versuche, einen passenden Typ für meine IDs in einem Go-Programm zu finden, das mit Uncle Bob Martins "Clean Architecture" entworfen wurde.Generischer ID-Typ für "Saubere Architektur" Go-Programm

type UserID ... 

type User struct { 
    ID UserID 
    Username string 
    ... 
} 

type UserRepository interface { 
    FindByID(id UserID) (*User, error) 
    ... 
} 

Ich folge Onkel Bob Martins "Clean Architecture", wo der Code als eine Reihe von Schichten organisiert ist (von außen nach innen: Infrastruktur, Schnittstellen, usecases und Domain) . Eines der Prinzipien ist die Abhängigkeitsregel: Quellcodeabhängigkeiten können nur nach innen zeigen.

Mein User Typ ist Teil des Domänen-Layers und daher kann der Typ ID nicht von der Datenbank abhängen, die für die UserRepository ausgewählt wurde; Wenn ich MongoDB verwende, könnte die ID eine ObjectId (string) sein, während ich in PostgreSQL eine ganze Zahl verwenden könnte. Der User Typ in der Domänenebene kann nicht wissen, was der Implementierungstyp sein wird.

Durch die Abhängigkeitsinjektion wird ein realer Typ (z. B. MongoUserRepository) die Schnittstelle UserRepository implementieren und die FindByID-Methode bereitstellen. Da diese MongoUserRepository in den Schnittstellen oder der Infrastrukturschicht definiert wird, kann sie von der Definition von UserRepository in der (mehr nach innen gerichteten) Domänenschicht abhängen.

Ich betrachtete

type UserID interface{} 

verwenden, aber dann wird der Compiler nicht sehr hilfreich sein, wenn Code in einen der äußeren Schicht versucht, in einem falschen Implementierung Typ zuordnen.

Ich möchte die Schnittstelle Layer oder Infrastruktur-Layer, wo die Datenbank angegeben ist, bestimmen und erfordern den spezifischen Typ für UserID, aber ich kann nicht den Domänen-Layer-Code importieren diese Informationen, weil das die Abhängigkeitsregel verletzt.

ich auch in Betracht gezogen (und bin derzeit)

type UserID interface { 
    String() string 
} 

aber das setzt die Kenntnis, dass die Datenbank-Strings für seine IDs verwenden (ich bin mit MongoDB mit seinem ObjectId - eine Art Synonym für string).

Wie kann ich dieses Problem idiomatisch behandeln, während der Compiler maximale Typsicherheit bietet und die Abhängigkeitsregel nicht verletzt?

Antwort

1

Vielleicht können Sie etwas wie folgt verwenden:

type UserID interface { 
    GetValue() string 
    SetValue(string) 
} 

Dann übernehmen Sie, dass Sie immer vorbei und String immer als ID (es Zeichenfolgeversion der Integer-ID bei PgSQL und andere RDBMS werden kann

type PgUserID struct { 
    value int 
} 

func (id *PgUserID) GetValue() string { 
    return strconv.Itoa(id.value) 
} 

func (id *PgUserID) SetValue(val string){ 
    id.value = strconv.Atoi(val) 
} 

type MongoUserID struct { 
    value string 
} 

func (id *MongoUserID) GetValue() string { 
    return value 
} 

func (id *MongoUserID) SetValue(val string){ 
    id.value = val 
} 

ich frage mich, ob dies erreicht, was Sie erreichen wollen, aber vielleicht ist es eleganter String-Konvertierungen in der Benutzer-ID zu verbergen:), und Sie UserID pro Datenbanktyp implementieren?

+1

Das könnte funktionieren. Ich werde darüber nachdenken.(Das ist eine Art von Ort, an dem ich mit meiner '' 'Type UserID Schnittstelle voranging. { String() String }' ''). – Ralph

+0

Ich glaube nicht, dass dies Kompilierzeit Typprüfung bietet. Ein 'PgUserRepository'-Typ 'FindByID'-Methode kann auch eine Zeichenkette' MongoUserID' akzeptieren. Oder jeder Typ, der die 'UesrID'-Schnittstelle implementiert. – abhink

+0

@abhink, wenn Sie Pg-spezifische Methode haben, warum würden Sie Schnittstelle anstelle von Strukturtyp als Argumenttyp in der FindByID-Methode verwenden? – Nebril

Verwandte Themen