CQRS-一度に複数のハンドラーで使用する必要があるコードをどうするか?







垂直スライススタイルでアーキテクチャを使用する場合遅かれ早かれ、「一度に複数のハンドラーで使用する必要があるコードが表示された場合はどうすればよいか」という疑問が生じます。







TLDR:ハンドラーミドルウェアを作成し、カスタムマーカーインターフェイスを追加して、どのハンドラーが全体的な抽象化であり、どのハンドラーがそうでないかを明確にする必要があります

この質問への答えは必ずしも明白ではありません。たとえば、Jimmy Boggardは、「リファクタリングだけ」を提案しています。私はこのアプローチを完全に支持しますが、答えの形式は、関数型プログラミングの依存性注入に無料のモナド使用するという提案と同じくらい落胆しているように思えますこのアドバイスは正確で短いですが、あまり役に立ちません。私はこの質問にもっと詳しく答えようとします。







リファクタリング



したがって、2つのリファクタリング手法を使用します。







  1. 抽出方法
  2. クラスを抽出する


, :







public IEnumerable<SomeDto> Handle(SomeQuery q)
{
    // 100  ,
    //     

    // 50  ,   
    //   

    return result;
}
      
      





, , 100 50 . , . «», ctrl+shift+r -> extract method . — .

, , - :







public IEnumerable<SomeDto> Handle(SomeQuery q)
{
    var shared = GetShared(q);
    var result = GetResult(shared);
    return result;
}
      
      





?



: ? . , :







public IEnumerable<SomeDto> Handle(SomeQuery q)
{
    var shared1 = GetShared1(q);
    var shared2 = GetShared2(q);
    var shared3 = GetShared3(q);
    var shared4 = GetShared4(q);

    var result = GetResult(shared1,shared2, shared3, shared4);
    return result;
}
      
      





.



, .







public class ConcreteQueryHandler: 
    IQueryHandler<SomeQuery, IEnumerable<SomeDto>>
{
    ??? _sharedHandler;

    public ConcreteQueryHandler(??? sharedHandler)
    {
        _sharedHandler = sharedHandler;
    }
}
      
      







///- (Domain Services). IDomainHandler<TIn, TOut>



, IHandler<TIn, TOut>



.







. . , — , .







.







public class ConcreteQueryHandler2:
    IQueryHandler<SomeQuery,  IEnumerable<SomeDto>>
{
    IDomainHandler<???, ???> _sharedHandler;

    public ConcreteQueryHandlerI(IDomainHandler<???, ???> sharedHandler)
    {
        _sharedHandler = sharedHandler;
    }
}

public class ConcreteQueryHandler2:
    IQueryHandler<SomeQuery,  IEnumerable<SomeDto>>
{
    IDomainHandler<???, ???> _sharedHandler;

    public ConcreteQueryHandlerI(IDomainHandler<???, ???> sharedHandler)
    {
        _sharedHandler = sharedHandler;
    }
}
      
      





?



, IHandler



. , , .









, , . , « ». , .




-: , IDomainHandler<???, ???>



. :







  1. ICommand/IQuery



    ?
  2. IQueryable<T>



    ?


ICommand/IQuery



?



, :







public interface ICommand<TResult>
{
}

public interface IQuery<TResult>
{
}
      
      





IDomainHandler



Command/Query



, .







IQueryable<T>



?



, ORM:) … LINQ LSP , — «». , , . IQueryable



— .









  1. コンストラクター引数としてドメインレイヤーの依存性を注入する


public class ConcreteQueryHandler:
    IQueryHandler<SomeQuery,  IEnumerable<SomeDto>>
{
    IDomainHandler<
        SomeValueObjectAsParam,
        IQueryable<SomeDto>>_sharedHandler;

    public ConcreteQueryHandler(
        IDomainHandler<
            SomeValueObjectAsParam,
            IQueryable<SomeDto>>)
    {
        _sharedHandler = sharedHandler;
    }

    public IEnumerable<SomeDto> Handle(SomeQuery q)
    {
        var prm = new SomeValueObjectAsParam(q.Param1, q.Param2);
        var shared = _sharedHandler.Handle(prm);

        var result = shared
          .Where(x => x.IsRightForThisUseCase)
          .ProjectToType<SomeDto>()
          .ToList();

        return result;
    }
}
      
      






All Articles