このスキーマで循環依存を回避したい:
DbRepository
には、IUserDbEntityFactory
エンティティを作成するためにUser
が必要です。IUserPublishedInfoInitializer
エンティティは、UserPublishedInfo
を作成するためにリクエストに応じて作成する必要があります。また、UserPublishedInfoInitializer
自体は、IDbRepository
にIsOnline
プロパティを設定するために、ユーザーが現在キャッシュに存在し、アクティブであるかどうかを確認するためにUserPublishedInfo
を必要とします。
CreateUser
メソッドとTryGetCachedUser
メソッドはどちらも、DbRepository
内のキャッシュやロックなどの同じ内部機能を使用します。
User
は、インターフェースのない集約ルートdbエンティティです。
DbRepository
にはIUserDbEntityFactory
が必要です。これにはIUserPublishedInfoInitializer
を構築してUser
を構築し、DbRepository
への循環依存関係を戻す必要があります。私は通常、コンストラクター依存性注入を使用しますが、この場合、循環依存性のために機能しません。そのため、これが問題です。
また、MakePublishedInfo
をUser
から移動したくありません。これは、実際にはC#の暗黙の会話であり、コードで非常に頻繁に使用されるためです。
そして、IDbRepository
をIUserPublishedInfoInitializer.Init
に引数として渡すことは、私が望むものではありません。なぜ、この実装は、それを使用しているものに依存する必要があるからですか?これはカプセル化を壊します。
スキーマでは、User
とUserPublishedInfo
のみが動的に作成されたオブジェクトです(その他は起動時に作成されます)。
このデザインを変更する必要がありますか?
IDbRepositoryのIUserPublishedInfoInitializerの依存関係を削除します。代わりに、これを構築パラメーターとして具体的なUserPublishedInfoInitializerに挿入します。
依存関係グラフは次のようになります
IUserPublishedInfoInitializer
IUserDbEntityFactory
User
IDbRepository
DbRepository
UserPublishedInfoInitializer
編集-
OK、DbRepositoryまたは子クラスに特別なコンストラクタが必要です
public DbRepository()
{
var upii = new UserPublishedInfoInitializer(this);
var this.userDbEntityFactory = new UserDbEntityFactory(upii);
}
それでもDIでやりたい場合は、DbRepositoryFactoryで同じことを行うことができます
public class DbRepositoryFactory : IDbRepositoryFactory
{
pulbic DbRepository Repo {get;set;}
}
public UserPublishedInfoInitializer(IDbRepositoryFactory repo)
{
var this.DbRepositoryFactory= repo.Repo; //dont use this yet!!!
}
public Main()
{
var dbfac = new DbRepositoryFactory()
var upii = new UserPublishedInfoInitializer(dbfac);
var repo = new DbRepository(upii)
dbfac.Repo = repo;
}
ただし、より多くのものを注入することが、リポジトリなしではUserオブジェクトを作成できないというコアの問題を本当に解決するかどうかはわかりません。
問題全体を見ずに言うのは難しいですが、名前からUserPublishedInfoInitializerは不要であるように見えますが、Userが実質的に集約ルートであり、常にUserPublishedInfoプロパティを持っている場合、リポジトリはUserPublishedInfoオブジェクトの作成を担当する可能性があります
循環依存問題に対するユビキタスな解決策は、オブザーバーパターンを導入することです。 1つの実装は、ドメインイベントを使用することです。
これが多すぎると思われる場合は、IDbRepository
依存関係をUserPublishedInfoInitializer
クラスにプロパティインジェクションで挿入してみてください。純粋なDIでは、次のようなものになります
var upi = new UserPublishedInfoInitializer();
var fac = new UserDbEntityFactory(upi);
var repo = new DbRepository(fac);
upi.DbRepository = repo;
ただし、これが最後の推奨ソリューションです。
TryGetCachedUser
メソッドをそのインターフェース(IUserCache
)に削除すると、循環依存関係を壊すことができると思います。 DbRepository
は、ユーザーがキャッシュに挿入されていることを確認し、UserPublishedInfoInitializer
はユーザーがキャッシュにあるかどうかを検査できます。