gpt4 book ai didi

interface - CQRS 模式 - 接口(interface)

转载 作者:行者123 更新时间:2023-12-01 07:18:01 25 4
gpt4 key购买 nike

我是 CQRS 模式的新手,但我想了解为什么应该使用两个接口(interface):

public interface IQuery{}
public interface ICommand{}

而不是只有一个接口(interface)(例如 IExecutable 或其他...)
比您还拥有一个处理程序(例如 IExecutionHandler 或其他...)

如果你愿意,你仍然可以把它分成一个 ICommandExecutionHandler 和一个 IQueryExecutionHandler

更新:尝试

下一个代码只是我如何看待它的一个例子。这可能是我完全错误的......所以请分享您的疑虑/我的错误。我只是想理解这一点。
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);
}
}

最佳答案

如果我理解正确,您会在这里混淆首字母缩写词。从您向我提出的问题看来,您并没有真正询问 Command and Query Responsibility Segregation。模式,但您可能会询问 Command-Query Separation原则。

在这种情况下,basics简而言之:

命令

Change the state of a system but do not return a value



查询

Return a result and do not change the observable state of the system (are free of side effects).



我将尝试演示具有泛型接口(interface)(及其实现)和非泛型接口(interface)之间的区别。此演示中显示的类似思维方式适用于通用查询处理程序。

解决您问题的技术方面

通用命令处理程序接口(interface)为:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}

它的示例实现:
public class ExampleCommandHandler : ICommandHandler<ExampleCommand> 
{
public void Handle(ExampleCommand command)
{
// Do whatever logic needed inside this command handler
}
}

示例 Command你传递给命令处理程序:
public class ExampleCommand
{
public int Id { get; set; }
public string Name { get; set; }
}

最后是命令处理程序的示例消费者:
public class ExampleService
{
private readonly ICommandHandler<ExampleCommand> commandHandler;

public ExampleService(ICommandHandler<ExampleCommand> handler)
{
commandHandler = handler;
}

public void DoStuff(int id, string name)
{
var command = new ExampleCommand
{
Id = id,
Name = name
};

commandHandler.Handle(command);
}
}

使用通用 ICommandHandler 的好处

使用通用命令处理程序让用户依赖于这种抽象,而不是完全实现的命令处理程序。

如果你会依赖这个 ExampleCommandHandler 的确切实现不会实现通用接口(interface),示例服务的构造函数将具有如下依赖项:
public ExampleService(ExampleCommandHandler handler)

在这种情况下,您无法装饰此处理程序,因为它没有实现接口(interface)。

另外值得注意的是,使用此设置,您只需对命令处理程序进行单元测试,而不需要对服务的 DoStuff() 进行单元测试。方法,因为行为在命令处理程序中。

关于 CQRS 的注意事项

这张图片中的 CQRS 与 CQS 等 OOP 方法在技术上有所不同。

关于interface - CQRS 模式 - 接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36428850/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com