如何不使用类助手,用多态或设计模式优雅处理外部库TPasElement派生类?
实现方案
以下三种方案均不需要修改外部类库代码、不使用类助手,可直接替换原有的分支判断逻辑。
方案1:类型字典映射法(适用于Delphi XE及以上版本)
利用泛型字典存储子类对应的处理逻辑,运行时直接通过类类型匹配对应处理方法,代码最简洁。
uses System.Generics.Collections, System.SysUtils; var // 字典键为子类类型,值为对应处理逻辑的匿名方法 ProcessHandlers: TDictionary<TClass, TProc<TPasElement>>; // 程序启动时初始化一次即可 procedure InitProcessHandlers; begin ProcessHandlers := TDictionary<TClass, TProc<TPasElement>>.Create; ProcessHandlers.Add(TPasConst, procedure(E: TPasElement) begin Writeln(TPasConst(E).ConstInfo); end); ProcessHandlers.Add(TPasVariable, procedure(E: TPasElement) begin Writeln(TPasVariable(E).VariableInfo); end); ProcessHandlers.Add(TPasType, procedure(E: TPasElement) begin Writeln(TPasType(E).TypeInfo); end); ProcessHandlers.Add(TPasProperty, procedure(E: TPasElement) begin Writeln(TPasProperty(E).PropertyInfo); end); ProcessHandlers.Add(TPasProcedure, procedure(E: TPasElement) begin Writeln(TPasProcedure(E).ProcedureInfo); end); end; // 最终调用的处理方法 procedure Process(Element: TPasElement); var Handler: TProc<TPasElement>; begin if not Assigned(Element) then Exit; if ProcessHandlers.TryGetValue(Element.ClassType, Handler) then Handler(Element); end;
- 优点:无冗余类型判断,新增子类支持仅需新增一行字典注册逻辑,代码量最少
- 缺点:需要Delphi版本支持匿名方法,更适合单一处理逻辑的场景
方案2:包装类继承多态方案(全版本兼容)
自定义一套包装类继承体系,通过多态特性实现逻辑分发,兼容所有Delphi版本。
// 包装类基类 type TElementWrapper = class abstract protected FElement: TPasElement; public constructor Create(AElement: TPasElement); procedure Process; virtual; abstract; end; // 各子类对应的包装类 TConstWrapper = class(TElementWrapper) public procedure Process; override; end; TVariableWrapper = class(TElementWrapper) public procedure Process; override; end; TTypeWrapper = class(TElementWrapper) public procedure Process; override; end; TPropertyWrapper = class(TElementWrapper) public procedure Process; override; end; TProcedureWrapper = class(TElementWrapper) public procedure Process; override; end; // 工厂函数:根据传入的元素返回对应包装类实例 function CreateElementWrapper(AElement: TPasElement): TElementWrapper; begin Result := nil; if not Assigned(AElement) then Exit; if AElement is TPasConst then Result := TConstWrapper.Create(AElement) else if AElement is TPasVariable then Result := TVariableWrapper.Create(AElement) else if AElement is TPasType then Result := TTypeWrapper.Create(AElement) else if AElement is TPasProperty then Result := TPropertyWrapper.Create(AElement) else if AElement is TPasProcedure then Result := TProcedureWrapper.Create(AElement); end; // 包装类实现 constructor TElementWrapper.Create(AElement: TPasElement); begin inherited Create; FElement := AElement; end; procedure TConstWrapper.Process; begin Writeln(TPasConst(FElement).ConstInfo); end; procedure TVariableWrapper.Process; begin Writeln(TPasVariable(FElement).VariableInfo); end; procedure TTypeWrapper.Process; begin Writeln(TPasType(FElement).TypeInfo); end; procedure TPropertyWrapper.Process; begin Writeln(TPasProperty(FElement).PropertyInfo); end; procedure TProcedureWrapper.Process; begin Writeln(TPasProcedure(FElement).ProcedureInfo); end; // 最终调用的处理方法 procedure Process(Element: TPasElement); var Wrapper: TElementWrapper; begin Wrapper := CreateElementWrapper(Element); if Assigned(Wrapper) then try Wrapper.Process; finally Wrapper.Free; end; end;
- 优点:完全符合面向对象多态设计,兼容所有Delphi版本,后续新增处理逻辑仅需在包装类中新增虚方法即可
- 缺点:需要额外定义一套包装类,类型判断逻辑收敛在工厂函数中,仅需修改一次
方案3:访问者模式(适合多处理逻辑场景)
如果需要对元素做多种不同处理(比如打印、导出XML、统计信息等),用访问者模式可以做到新增处理逻辑不修改原有代码。
// 访问者基类 type TElementVisitor = class abstract public procedure VisitConst(Element: TPasConst); virtual; abstract; procedure VisitVariable(Element: TPasVariable); virtual; abstract; procedure VisitType(Element: TPasType); virtual; abstract; procedure VisitProperty(Element: TPasProperty); virtual; abstract; procedure VisitProcedure(Element: TPasProcedure); virtual; abstract; // 调度方法,统一做类型判断 procedure Dispatch(Element: TPasElement); end; // 具体的打印处理访问者 type TPrintVisitor = class(TElementVisitor) public procedure VisitConst(Element: TPasConst); override; procedure VisitVariable(Element: TPasVariable); override; procedure VisitType(Element: TPasType); override; procedure VisitProperty(Element: TPasProperty); override; procedure VisitProcedure(Element: TPasProcedure); override; end; procedure TElementVisitor.Dispatch(Element: TPasElement); begin if Element is TPasConst then VisitConst(TPasConst(Element)) else if Element is TPasVariable then VisitVariable(TPasVariable(Element)) else if Element is TPasType then VisitType(TPasType(Element)) else if Element is TPasProperty then VisitProperty(TPasProperty(Element)) else if Element is TPasProcedure then VisitProcedure(TPasProcedure(Element)); end; // 打印访问者逻辑实现 procedure TPrintVisitor.VisitConst(Element: TPasConst); begin Writeln(Element.ConstInfo); end; procedure TPrintVisitor.VisitVariable(Element: TPasVariable); begin Writeln(Element.VariableInfo); end; procedure TPrintVisitor.VisitType(Element: TPasType); begin Writeln(Element.TypeInfo); end; procedure TPrintVisitor.VisitProperty(Element: TPasProperty); begin Writeln(Element.PropertyInfo); end; procedure TPrintVisitor.VisitProcedure(Element: TPasProcedure); begin Writeln(Element.ProcedureInfo); end; // 最终调用的处理方法 procedure Process(Element: TPasElement); var Visitor: TPrintVisitor; begin Visitor := TPrintVisitor.Create; try Visitor.Dispatch(Element); finally Visitor.Free; end; end;
- 优点:扩展性极强,新增处理逻辑仅需新增访问者子类,不需要修改原有调度逻辑
- 缺点:结构相对复杂,适合处理逻辑较多的中大型项目
内容的提问来源于stack exchange,提问作者simone
相关产品推荐
相关产品推荐

