Cuando se usa la arquitectura en el estilo de cortes verticales, tarde o temprano surge la pregunta "¿qué hacer si aparece un código que debe usarse en varios controladores a la vez?"
TLDR: debe crear un middleware de controlador y agregar interfaces de marcador personalizadas para dejar en claro qué controladores son abstracciones holísticas y cuáles no.
La respuesta a esta pregunta no siempre es obvia. Jimmy Boggard, por ejemplo, sugiere " simplemente refactorizar ". Apoyo totalmente este enfoque, pero la forma de la respuesta me parece tan desalentadora como la propuesta de usar una mónada libre para la inyección de dependencia en la programación funcional . Este consejo es preciso y breve, pero no muy útil. Intentaré responder esta pregunta con más detalle.
Refactorización
Entonces, usaré dos técnicas de refactorización:
- Método de extracción
- Clase de extracto
, :
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
— .
- Inyectando la dependencia de la capa de dominio como argumentos del constructor
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;
}
}