代码之家  ›  专栏  ›  技术社区  ›  stanleyxu2005

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

  •  1
  • stanleyxu2005  · 技术社区  · 15 年前

    我想实现一个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;
    

    根据代码,不同请求类型的处理非常相似。如果我有100种不同的请求类型,我必须复制并粘贴上面的代码块100次。这可不聪明。我正在寻找一个更好的方法来做同样的逻辑。我的想象如下:

    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;
    

    我不知道,如果我能写一个通用的方式来处理大量不同的请求类型。开发环境delphi2010。

    任何暗示都将不胜感激。

    1 回复  |  直到 15 年前
        1
  •  1
  •   Rob Kennedy    15 年前

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

    你用的是化装版 TClassInfo 元类 代表您的请求类。我想 TAaaRequest TBbbRequest (以及其他100个请求类)都是从某个基础上派生出来的 TRequest TRequestClass 这样地:

    type
      TRequestClass = class of TRequest;
    

    这个 FromJSON 方法对每个类都有不同的作用,对吗?如果是这样,那么它应该是虚拟的(如果该方法在每个类中执行相同的操作,那么它就不会执行 不管别人怎么说,你都不必强制转换构造函数的结果;简单声明 Info 作为一个 特雷奎斯特 而不是 TObject .

    IRequestHandler 特雷奎斯特 ,如果没有一个巨大的 if - else 检查每个可能的等级。

    相反,请再次使用虚拟分派。给每个 特雷奎斯特 Handle 方法,因此类声明如下所示:

    type
      TRequest = class
      public
        constructor FromJSON(const json: string);
        function Handle: TResponse; virtual; abstract;
      end;
    

    实施 手柄 每一个后代,你就完了。最终 IRequestHandler程序

    IRequestHandler程序 方法,或者有许多请求处理程序对象都实现同一个接口,并以决定要创建哪个请求类的相同方式来决定要创建哪个接口。然后将request对象交给request handler对象,让它们一起工作。

    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;
    

    然后将请求传递给处理程序:

    Result := Handler.Handle(Request);