Patrón CQRS - interfaces
Soy nuevo en el patrón CQRS, pero me gustaría entender por qué debería usar dos interfaces:
public interface IQuery{}
public interface ICommand{}
En lugar de una sola interfaz (por ejemplo, IExecutable, o lo que sea ...)
Entonces también tiene un controlador (por ejemplo, IExecutionHandler, o lo que sea ...)
Y si lo desea, aún puede dividirlo en un ICommandExecutionHandler y un IQueryExecutionHandler
Actualización: un intento
El siguiente código es solo un ejemplo de cómo lo veo. Es posible que esté completamente equivocado con esto ... así que por favor comparta sus preocupaciones / mis fallas. Solo estoy tratando de entender esto.
public interface IExecutable { }
public interface ICommand : IExecutable { }
public interface IReturnCommand<TOutput>: ICommand
{
TOutput Result { get; set; }
}
public interface IQuery<TOutput>: IExecutable
{
TOutput Result { get; set; }
}
public interface IExecutionHandler<in T>: IDisposable where T : IExecutable
{
void Execute(T executable);
}
public class CreateAttachments : IReturnCommand<List<Guid>>
{
public List<Attachment> Attachments { get; set; }
public List<Guid> Result { get; set; }
}
public abstract class BaseExecutionHandler : IDisposable
{
protected readonly IUnitOfWork UnitOfWork;
private bool _disposed;
protected BaseExecutionHandler(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
UnitOfWork.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class AttachmentCommandHandler : BaseExecutionHandler,
IExecutionHandler<CreateAttachments>
{
public AttachmentCommandHandler(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
public void Execute(CreateAttachments command)
{
command.Result = command.Attachments.Select(x => UnitOfWork.Create(x)).ToList();
}
}
public interface IProcessor : IDisposable
{
void Process<TExecutable>(TExecutable command) where TExecutable : IExecutable;
}
public class Processor : IProcessor
{
private readonly Dictionary<IExecutable, IExecutionHandler<IExecutable>> _handlers;
private readonly IUnitOfWork _unitOfWork;
private bool _disposed;
public Processor(IUnitOfWork unitOfWork)
{
_handlers = new Dictionary<IExecutable, IExecutionHandler<IExecutable>>();
_unitOfWork = unitOfWork;
}
private IExecutionHandler<IExecutable> GetHandler<TExecutable>(TExecutable executable) where TExecutable: IExecutable
{
if (_handlers.ContainsKey(executable))
{
return _handlers[executable];
}
var handlerType = typeof(IExecutionHandler<>).MakeGenericType(executable.GetType());
var handler = Activator.CreateInstance(handlerType, _unitOfWork) as IExecutionHandler<IExecutable>;
_handlers.Add(executable, handler);
return handler;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
foreach (var handler in _handlers.Values)
{
handler.Dispose();
}
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Process<TExecutable>(TExecutable executable) where TExecutable : IExecutable
{
var handler = GetHandler(executable);
handler.Execute(executable);
}
}
public class AttachmentController : ApiController
{
private readonly IProcessor _processor;
public AttachmentController(IProcessor processor)
{
_processor = processor;
}
public List<Guid> Post(List<Attachment> attachments)
{
var command = new CreateAttachments { Attachments = attachments };
_processor.Process(command);
return command.Result;
}
[EnableQuery]
public IQueryable<Attachment> Get()
{
var query = new GetAllAttachments { };
_processor.Process(query);
return query.Result;
}
protected override void Dispose(bool disposing)
{
_processor.Dispose();
base.Dispose(disposing);
}
}