
Ao usar arquitetura no estilo de fatias verticais, mais cedo ou mais tarde surge a questão "o que fazer se aparecer um código que precise ser usado em vários manipuladores ao mesmo tempo?"
TLDR: você precisa criar um middleware de manipulador e adicionar interfaces de marcador personalizadas para deixar claro quais manipuladores são abstrações holísticas e quais não são.
A resposta a esta pergunta nem sempre é óbvia. Jimmy Boggard, por exemplo, sugere " apenas refatorar ". Eu apoio totalmente essa abordagem, mas a forma da resposta me parece tão desanimadora quanto a proposta de usar uma mônada livre para injeção de dependência na programação funcional . Este conselho é preciso e curto, mas não muito útil. Tentarei responder a essa pergunta com mais detalhes.
Reestruturação
Portanto, usarei duas técnicas de refatoração:
, :
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<???, ???>
. :
-
ICommand/IQuery
? -
IQueryable<T>
?
ICommand/IQuery
?
public interface ICommand<TResult>
{
}
public interface IQuery<TResult>
{
}
IDomainHandler
Command/Query
, .
IQueryable<T>
?
, ORM:) … LINQ LSP , — «». , , . IQueryable
— .
- Injetando a dependência da camada de domínio como argumentos do construtor
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;
}
}