【发布时间】:2021-09-23 19:28:42
【问题描述】:
我必须首先承认我来自 .Net 世界,目前正在重新学习 Delphi (XE 10.x)(从高中开始 - 许多年前)。在 .Net 中,中介者模式由 MediatR 或 MassTransit 等库很好地处理。然而,我发现很少有库支持在 Delphi 中动态(或半动态)实现中介者模式。没有去扫描正在执行的 Rtti 信息的花哨级别,我想创建一个简单的中介,我可以通过请求注册一个 CommandHandler,然后得到一个响应。这可能吗?
这是迄今为止我编写的一些示例代码 - 但我只是陷入了如何动态创建对象以及我的方法是否合理的问题。
在检查代码之前,我并没有坚持使用 TDictionary
// interface
uses
System.Generics.Collections;
type
TUnit = record
end;
IRequest<TResponse> = interface
end;
IRequest = interface(IRequest<TUnit>)
end;
IRequestHandler<TResponse; TRequest: IRequest<IResponse>> = interface(IInvokable)
function Handle(ARequest: TRequest): TResponse;
end;
IRequestHandler<TRequest: IRequest<TUnit>> = interface(IRequestHandler<TUnit, TRequest>)
end;
TMediator = class
private
FRequestHandlers: TDictionary<string, string>;
public
constructor Create;
destructor Destroy; override;
procedure RegisterHandler(AHandlerClass, ARequestClass: TClass);
function Send<TResponse, TRequest>(ARequest: TRequest): TResponse;
end;
// implementation
constructor TMediator.Create;
begin
Self.FRequestHandlers := TDictionary<string, string>.Create;
end;
destructor TMediator.Destroy;
begin
Self.FRequestHandlers.Free;
inherited;
end;
procedure TMediator.RegisterHandler(AHandlerClass, ARequestClass: TClass);
var
LTempRequestClass : string;
rContext : TRttiContext;
rType : TRttiType;
begin
if Self.FRequestHandlers.TryGetValue(ARequestClass.QualifiedClassName, LTempRequestClass) then
exit;
{ I would like to add some error checking functionality to prevent classes
that do not implement IRequest or IRequest<> from being added here. }
Self.FRequestHandlers.Add(ARequestClass.QualifiedClassName, AHandlerClass.QualifiedClassName);
end;
function TMediator.Send<TResponse, TRequest>(ARequest: TRequest): TResponse;
var
LRequestHandlerClassName: string;
LRequestHandler : IRequestHandler<TResponse, TRequest>;
begin
if not Self.FRequestHandlers.TryGetValue(ARequest.QualifiedClassName, LRequestHandlerClassName) then
raise Exception.Create('Handler class not registered with this mediator.');
{ Not sure what to do here to get the LRequestHandler - I'm also using Spring4d,
so I considered using the QualifiedClassName as a way to resolve classes
registered in the TContainer }
Result := LRequestHandler.Handle(ARequest);
end;
我对此的预期用法是:
注意:下面的编辑 - 我希望能够从单个主持人注册和调用任何实现 IRequest 或 IRequest 的命令。
// interface
type
TMyResponse = class
private
FFoo: string;
public
property Foo: string read FFoo write FFoo;
end;
TMyResponse2 = class
private
FFoo2: string;
public
property Foo2: string read FFoo2 write FFoo2;
end;
TMyRequest = class(TInterfacedObject, IRequest<TMyResponse>)
private
FBar: string;
public
property Bar: string read FBar write FBar;
end;
TMyRequest2 = class(TInterfacedObject, IRequest<TMyResponse2>)
private
FBar2: string;
public
property Bar2: string read FBar2 write FBar2;
end;
TMyRequestHandler = class(TInterfacedObject, IRequestHandler<TMyResponse, TMyRequest>)
public
function Handle(ARequest: TMyRequest): TMyResponse;
end;
TMyRequestHandler2 = class(TInterfacedObject, IRequestHandler<TMyResponse2, TMyRequest2>)
public
function Handle(ARequest: TMyRequest2): TMyResponse2;
end;
// implementation
var
AMediator: TMediator;
ARequest: TMyRequest;
ARequest2: TMyRequest2;
AResponse: TMyResponse;
AResponse2: TMyResponse2;
begin
AMediator := TMediator.Create;
ARequest := TMyRequest.Create;
ARequest2 := TMyRequest2.Create;
try
ARequest.Bar := 'something';
ARequest2.Bar2 := 'else';
// Not sure how I would get these either - seems best to use the qualified class name
AMediator.Register(TMyRequestHandler.QualifiedClassName, TMyRequest.QualifiedClassName);
AMediator.Register(TMyRequestHandler2.QualifiedClassName, TMyRequest2.QualifiedClassName);
AResponse := AMediator.Send(ARequest);
AResponse2 := AMediator.Send(ARequest2);
// Do something with this value
finally
AResponse2.Free;
AResponse.Free;
ARequest2.Free;
ARequest.Free;
AMediator.Free;
end;
end.
【问题讨论】:
-
这里的问题太多了。
TMediator包含通用元素,因此应声明为TMediator<T, R> = class,其中相应地为function Send<T, R>(ARequest: R): T。当您创建它时,它将是TMediator<TMyResponse, TMyRequest>.Create;- 不需要 RTTI。您可以使用generic constraints 确保只允许支持所需接口的类,即:TMediator<T, R : IRequest> = class。作为一个问题,我认为总体上需要更多关注。 -
我很抱歉,并会澄清这个问题。这个 TModerator 的想法(参考我正在使用的 C# 中的示例)是从 TRequest 或 TRequest 的任何后代注册和执行处理程序,而不仅仅是单个方法。我会澄清这个帖子。感谢您的反馈。
-
这很难理解,因为您错误地使用了通用语法。其中大部分不是有效的 Delphi,这是 100% 抽象代码,因此很难遵循您的意图。此处代码中表达的内容大多是无意义的。这将有助于理解这个试图解决的问题。如果是在 Delphi 中重写一个库,我认为问题需要更具体。
标签: delphi design-patterns delphi-10.3-rio spring4d