3

Uncle Bob Martin の「Clean Architecture」を使用して設計された Go プログラムで、ID の適切なタイプを見つけようとしています。

type UserID ...

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

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

私は Uncle Bob Martin の「クリーン アーキテクチャ」に従っています。ここでは、コードが一連のレイヤーとして編成されています (外部から:インフラストラクチャインターフェイスユースケース、およびドメイン)。原則の 1 つは依存関係の規則です。ソース コードの依存関係は内側のみを指すことができます

私のUserタイプはドメイン層の一部であるため、IDタイプは のために選択されたデータベースに依存することはできませんUserRepository。MongoDB を使用している場合、ID はObjectId( string) である可能性がありますが、PostgreSQL では整数を使用する可能性があります。ドメイン層のUser型は、実装する型が何であるかを知ることができません。

依存性注入により、実際の型 (例: ) がインターフェイスMongoUserRepositoryを実装し、メソッドを提供します。これはインターフェイスまたはインフラストラクチャ層で定義されるため、(より内側の) ドメイン層での定義に依存する可能性があります。UserRepositoryFindByIDMongoUserRepositoryUserRepository

使用を検討しました

type UserID interface{}

ただし、外側の層のいずれかのコードが誤った実装型を割り当てようとすると、コンパイラはあまり役に立ちません。

データベースが指定されているインターフェイス レイヤーまたはインフラストラクチャ レイヤーで特定のタイプを決定して要求したいのですUserIDが、ドメイン レイヤー コードにその情報をインポートさせることはできません。依存関係の規則に違反するからです。

私も検討しました(そして現在使用しています)

type UserID interface {
    String() string
}

ただし、これは、データベースが ID に文字列を使用するという知識を前提としています (私は MongoDB をObjectId-- の型シノニムで使用していますstring)。

コンパイラが最大限の型安全性を提供し、依存関係の規則に違反しないようにしながら、慣用的な方法でこの問題を処理するにはどうすればよいですか?

4

3 に答える 3

1

たぶん、次のようなものを使用できます。

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

次に、常に ID として文字列を渡したり取得したりしていると仮定し (PgSQL やその他の RDBMS の場合は整数 ID を文字列化したバージョンにすることができます)、データベースの種類ごとに UserID を実装します。

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
}

これであなたが達成したいことが達成されるのだろうかと思いますが、UserID 内に文字列変換を隠す方がエレガントでしょうか?

于 2016-07-06T13:08:50.933 に答える