web-dev-qa-db-ja.com

循環依存関係の排除

このスキーマで循環依存を回避したい:

Diagram

DbRepositoryには、IUserDbEntityFactoryエンティティを作成するためにUserが必要です。IUserPublishedInfoInitializerエンティティは、UserPublishedInfoを作成するためにリクエストに応じて作成する必要があります。また、UserPublishedInfoInitializer自体は、IDbRepositoryIsOnlineプロパティを設定するために、ユーザーが現在キャッシュに存在し、アクティブであるかどうかを確認するためにUserPublishedInfoを必要とします。

CreateUserメソッドとTryGetCachedUserメソッドはどちらも、DbRepository内のキャッシュやロックなどの同じ内部機能を使用します。

Userは、インターフェースのない集約ルートdbエンティティです。

DbRepositoryにはIUserDbEntityFactoryが必要です。これにはIUserPublishedInfoInitializerを構築してUserを構築し、DbRepositoryへの循環依存関係を戻す必要があります。私は通常、コンストラクター依存性注入を使用しますが、この場合、循環依存性のために機能しません。そのため、これが問題です。

また、MakePublishedInfoUserから移動したくありません。これは、実際にはC#の暗黙の会話であり、コードで非常に頻繁に使用されるためです。

そして、IDbRepositoryIUserPublishedInfoInitializer.Initに引数として渡すことは、私が望むものではありません。なぜ、この実装は、それを使用しているものに依存する必要があるからですか?これはカプセル化を壊します。

スキーマでは、UserUserPublishedInfoのみが動的に作成されたオブジェクトです(その他は起動時に作成されます)。

このデザインを変更する必要がありますか?

3
Vlad

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
Ewan

循環依存問題に対するユビキタスな解決策は、オブザーバーパターンを導入することです。 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はユーザーがキャッシュにあるかどうかを検査できます。

0
Adrian Iftode