
Bei der Verwendung von Architektur im Stil vertikaler Slices stellt sich früher oder später die Frage: "Was tun, wenn Code angezeigt wird, der in mehreren Handlern gleichzeitig verwendet werden muss?"
TLDR: Sie müssen eine Handler-Middleware erstellen und benutzerdefinierte Markierungsschnittstellen hinzufügen, um zu verdeutlichen, welche Handler ganzheitliche Abstraktionen sind und welche nicht.
Die Antwort auf diese Frage ist nicht immer offensichtlich. Jimmy Boggard schlägt zum Beispiel vor, " nur umzugestalten" . Ich unterstütze diesen Ansatz voll und ganz, aber die Form der Antwort erscheint mir ebenso entmutigend wie der Vorschlag, eine freie Monade für die Abhängigkeitsinjektion in der funktionalen Programmierung zu verwenden . Dieser Rat ist präzise und kurz, aber nicht sehr hilfreich. Ich werde versuchen, diese Frage genauer zu beantworten.
Refactoring
Ich werde also zwei Refactoring-Techniken verwenden:
, :
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
— .
- Injizieren der Domänenschichtabhängigkeit als Konstruktorargumente
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;
}
}