delphi中消息译码器的设计建议

delphi中消息译码器的设计建议,delphi,class,templates,methods,Delphi,Class,Templates,Methods,我想实现一个RPC模块。不同的请求被编码为JSON对象。它们将被解码,然后由请求处理程序处理。最后将返回相应的响应。演示代码如下所示: type IRequestHandler = interface function Handle(const Request: TAaaRequest): TResponse; function Handle(const Request: TBbbRequest): TResponse; end; TDecoder = class

我想实现一个RPC模块。不同的请求被编码为JSON对象。它们将被解码,然后由请求处理程序处理。最后将返回相应的响应。演示代码如下所示:

type
  IRequestHandler = interface
    function Handle(const Request: TAaaRequest): TResponse;
    function Handle(const Request: TBbbRequest): TResponse;
  end;

  TDecoder = class
    class function Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
  end;

class function TDecoder.Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
var
  Method: string;
  Request: TObject;
begin
  Method := Json['method'].AsString;
  if (Method = TAaaRequest.ClassName) then
  begin
    Request := TAaaRequest.FromJSON(Json); // Casted as TObject
    if Request <> nil then
    begin
      Result := RequestHandler.Handle(TAaaRequest(Request));
      Request.Free;
    end;
  end
  else if (Method = TBbbRequest.ClassName) then
  begin
    Request := TBbbRequest.FromJSON(Json); // Casted as TObject
    if Request <> nil then
    begin
      Result := RequestHandler.Handle(TBbbRequest(Request));
      Request.Free;
    end;
  end
  else
    Result := CreateErrorResponse('Unknown method: ' + Json.ToString);
end;
TDecoder = class
private
  FRequestTypes: TDictionary<string, TClassInfo>; // Does this work?
public
  constructor Create;
  destructor Destroy; override;
  function Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
end;

constructor TDecoder.Create;
begin
  FRequestTypes := TDictionary<string, TClassInfo>.Create;
  FRequestTypes.Add(TAaaRequest.ClassName, TAaaRequest); // Does this work?
  FRequestTypes.Add(TBbbRequest.ClassName, TBbbRequest); 
end;

destructor TDecoder.Destroy;
begin
  FRequestTypes.Free;
  inherited;
end;

function TDecoder.Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
var
  Method: string;
  Info: TClassInfo;
  Request: TObject;
begin
  Method := Json['method'].AsString;
  if FRequestTypes.ContainsKey(Method) then
  begin
    // An universal way
    Info := FRequestTypes[Method];
    Request := Info.FromJSON(Json); // Casted as TObject
    if Request <> nil then
    begin
      Result := RequestHandler.Handle(Info(Request)); // Casted to corresponding class type (e.g. TAaaRequest or TBbbRequest)
      Request.Free;
    end;
  end
  else
    Result := CreateErrorResponse('Unknown method: ' + Json.ToString);
end;
类型
IRequestHandler=接口
函数句柄(const请求:TAaaRequest):t响应;
函数句柄(const请求:TBbbRequest):t响应;
结束;
TDecoder=类
类函数Decode(constjson:TJsonObject;constrequesthandler:IRequestHandler):t响应;
结束;
类函数TDecoder.Decode(constjson:TJsonObject;constrequesthandler:IRequestHandler):treponse;
变量
方法:字符串;
请求:TObject;
开始
方法:=Json['Method'].AsString;
如果(Method=TAaaRequest.ClassName),那么
开始
请求:=TAaaRequest.FromJSON(Json);//铸造为对象
如果请求为零,则
开始
结果:=RequestHandler.Handle(TAaaRequest(Request));
请求。免费;
结束;
结束
否则如果(Method=TBbbRequest.ClassName),则
开始
请求:=TBbbRequest.FromJSON(Json);//铸造为对象
如果请求为零,则
开始
结果:=RequestHandler.Handle(TBbbRequest(Request));
请求。免费;
结束;
结束
其他的
结果:=CreateErrorResponse('Unknown method:'+Json.ToString);
结束;
根据代码,不同请求类型的处理非常相似。如果我有100种不同的请求类型,我必须复制并粘贴上面的代码块100次。这并不聪明。我正在寻找一种更好的方法来实现同样的逻辑。我的想象如下:

type
  IRequestHandler = interface
    function Handle(const Request: TAaaRequest): TResponse;
    function Handle(const Request: TBbbRequest): TResponse;
  end;

  TDecoder = class
    class function Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
  end;

class function TDecoder.Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
var
  Method: string;
  Request: TObject;
begin
  Method := Json['method'].AsString;
  if (Method = TAaaRequest.ClassName) then
  begin
    Request := TAaaRequest.FromJSON(Json); // Casted as TObject
    if Request <> nil then
    begin
      Result := RequestHandler.Handle(TAaaRequest(Request));
      Request.Free;
    end;
  end
  else if (Method = TBbbRequest.ClassName) then
  begin
    Request := TBbbRequest.FromJSON(Json); // Casted as TObject
    if Request <> nil then
    begin
      Result := RequestHandler.Handle(TBbbRequest(Request));
      Request.Free;
    end;
  end
  else
    Result := CreateErrorResponse('Unknown method: ' + Json.ToString);
end;
TDecoder = class
private
  FRequestTypes: TDictionary<string, TClassInfo>; // Does this work?
public
  constructor Create;
  destructor Destroy; override;
  function Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
end;

constructor TDecoder.Create;
begin
  FRequestTypes := TDictionary<string, TClassInfo>.Create;
  FRequestTypes.Add(TAaaRequest.ClassName, TAaaRequest); // Does this work?
  FRequestTypes.Add(TBbbRequest.ClassName, TBbbRequest); 
end;

destructor TDecoder.Destroy;
begin
  FRequestTypes.Free;
  inherited;
end;

function TDecoder.Decode(const Json: TJsonObject; const RequestHandler: IRequestHandler): TResponse;
var
  Method: string;
  Info: TClassInfo;
  Request: TObject;
begin
  Method := Json['method'].AsString;
  if FRequestTypes.ContainsKey(Method) then
  begin
    // An universal way
    Info := FRequestTypes[Method];
    Request := Info.FromJSON(Json); // Casted as TObject
    if Request <> nil then
    begin
      Result := RequestHandler.Handle(Info(Request)); // Casted to corresponding class type (e.g. TAaaRequest or TBbbRequest)
      Request.Free;
    end;
  end
  else
    Result := CreateErrorResponse('Unknown method: ' + Json.ToString);
end;
TDecoder=class
私有的
频率类型:t字典;//这行吗?
公众的
构造函数创建;
毁灭者毁灭;推翻
函数解码(constjson:TJsonObject;constrequesthandler:IRequestHandler):t响应;
结束;
构造函数TDecoder.Create;
开始
FRequestTypes:=t字典。创建;
添加(TAaaRequest.ClassName,TAaaRequest);//这行吗?
添加(TBbbRequest.ClassName,TBbbRequest);
结束;
销毁器TDecoder.Destroy;
开始
FRequestTypes.Free;
继承;
结束;
函数TDecoder.Decode(constjson:TJsonObject;constrequesthandler:IRequestHandler):t响应;
变量
方法:字符串;
资讯:TClassInfo ;;
请求:TObject;
开始
方法:=Json['Method'].AsString;
如果FRequestTypes.ContainsKey(方法),则
开始
//普遍的方式
信息:=频率类型[方法];
请求:=Info.FromJSON(Json);//铸造为对象
如果请求为零,则
开始
结果:=RequestHandler.Handle(信息(请求));//铸造到相应的类别类型(如TAaaRequest或TBbbRequest)
请求。免费;
结束;
结束
其他的
结果:=CreateErrorResponse('Unknown method:'+Json.ToString);
结束;
我不知道,我是否可以编写一种通用的方法来处理大量不同的请求类型。开发环境Delphi2010


感谢您的任何提示。

您的第二次尝试非常接近。你只遗漏了几个细节

如果使用了组合类型
TClassInfo
,则需要定义一个元类来表示请求类。我假设
TAaaRequest
TBbbRequest
(以及其他100个请求类)都来自某个基本
TRequest
类。定义
TRequestClass
如下:

type
  TRequestClass = class of TRequest;
type
  TRequest = class
  public
    constructor FromJSON(const json: string);
    function Handle: TResponse; virtual; abstract;
  end;
FromJSON
方法对每个类都有不同的作用,对吗?如果是这样,那么它应该是虚拟的。(如果该方法在每个类中执行相同的操作,那么它不必是虚拟的,不管其他人会告诉你什么。)您不必对构造函数的结果进行类型转换;只需将
Info
声明为
TRequest
,而不是
TObject

您需要做的最大更改是
IRequestHandler
接口。由于您的每个对象都是一个
TRequest
,如果没有一个巨大的
if
-
else
梯形图来检查每个可能的类,那么将其分派到正确的接口方法将非常笨拙

相反,请再次使用虚拟分派。为每个
TRequest
对象指定一个虚拟
Handle
方法,因此类声明如下所示:

type
  TRequestClass = class of TRequest;
type
  TRequest = class
  public
    constructor FromJSON(const json: string);
    function Handle: TResponse; virtual; abstract;
  end;
为每个子代实现
Handle
,就完成了。最终,
IRequestHandler
接口可以消失。您已经将处理能力写入了每个请求类中。您不需要一个类来表示请求,而需要另一个类来处理它

如果您想拥有一个单独的处理类,那么您可以使用现有的处理类,其中您将有一个大条件来决定要调用哪个
IRequestHandler
方法,或者您有许多请求处理程序对象都实现了相同的接口,您决定创建哪个请求类的方式与决定创建哪个请求类的方式相同。然后将请求对象交给请求处理程序对象,让它们一起工作

例如,定义处理程序接口:

type
  IRequestHandler = interface
    function Handle(request: TRequest): TResponse;
  end;
像注册请求一样注册处理程序:

// Use the same names as the requests, but a different dictionary
FRequestHandlers.Add(TAaaRequest.ClassName, TAaaHandler);
FRequestHandlers.Add(TBbbRequest.ClassName, TBbbHandler);
HandlerType := FRequestHandlers[Method];
HandlerObject := HandlerType.Create;
if not Supports(HandlerObject, IRequestHandler, Handler) then
  exit;
像处理请求一样实例化处理程序:

// Use the same names as the requests, but a different dictionary
FRequestHandlers.Add(TAaaRequest.ClassName, TAaaHandler);
FRequestHandlers.Add(TBbbRequest.ClassName, TBbbHandler);
HandlerType := FRequestHandlers[Method];
HandlerObject := HandlerType.Create;
if not Supports(HandlerObject, IRequestHandler, Handler) then
  exit;
然后将请求传递给处理程序:

Result := Handler.Handle(Request);

你的第二次尝试非常接近。你只遗漏了几个细节

如果使用了组合类型
TClassInfo
,则需要定义一个元类来表示请求类。我假设
TAaaRequest
TBbbRequest
(以及其他100个请求类)都来自某个基本
TRequest
类。定义
TRequestClass
如下:

type
  TRequestClass = class of TRequest;
type
  TRequest = class
  public
    constructor FromJSON(const json: string);
    function Handle: TResponse; virtual; abstract;
  end;
FromJSON
方法对每个类都有不同的作用,对吗?如果是这样,那么它应该是虚拟的。(如果该方法在每个类中执行相同的操作,那么它不必是虚拟的,不管其他人可能会告诉你什么。)您不必键入并强制转换co的结果