delphi中消息译码器的设计建议
我想实现一个RPC模块。不同的请求被编码为JSON对象。它们将被解码,然后由请求处理程序处理。最后将返回相应的响应。演示代码如下所示: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
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的结果