design suggestion for a message decoder in delphi

Posted by stanleyxu2005 on Stack Overflow See other posts from Stack Overflow or by stanleyxu2005
Published on 2010-04-06T03:23:02Z Indexed on 2010/04/06 3:33 UTC
Read the original article Hit count: 309

Filed under:
|
|
|
|

Hi All,

I want to implement a RPC module. Different requests are encoded as JSON objects. They will be decoded and then be handled by a request handler. At last a corresponding response will be returned. The demo code looks as follows:

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;

According to the code, the handling of different request types are very similar. If I have 100 different request types, I have to copy and paste the above code block 100 times. This is not clever. I am looking for a better way to do the same logic. My imagination is as follows:

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;

I do not know, if I can write an universal way to handle a great number of different request types. Development environment Delphi 2010.

Any hint is appreciated.

© Stack Overflow or respective owner

Related posts about delphi

Related posts about template