如何让Delphi子类拥有独立的class var静态字段值而非共享?
问题原因
Delphi中,基类定义的class var默认属于类级别的共享存储,所有子类会共用基类的这个字段内存空间。因此当你先给TCustomers.ResourceName赋值为'customers/',再给TArticles.ResourceName赋值为'articles/'时,后者会覆盖前者的内容,导致所有子类访问的都是最后赋值的那个值。
解决方案
可以通过两种方式实现每个子类持有独立的静态字段值:
方案一:子类重新声明class var
在每个子类中重新声明ResourceName字段,这样每个子类会拥有独立的静态存储区域,不会与基类或其他子类共享。
代码示例
基类定义:
TKpModelViewControllerEntity = class protected class var ResourceName: string; public procedure Manage; virtual; end; procedure TKpModelViewControllerEntity.Manage; begin // 注意:若基类方法直接访问ResourceName,会使用基类的字段值 // 如需访问子类的字段,需在子类中重写Manage方法 Writeln(ResourceName); end;
子类TCustomers:
TCustomers = class(TKpModelViewControllerEntity) protected class var ResourceName: string; // 重新声明,独立存储 public constructor Create; override; procedure Manage; override; end; constructor TCustomers.Create; begin inherited; ResourceName := 'customers/'; end; procedure TCustomers.Manage; begin Writeln(ResourceName); // 访问子类自己的静态字段 end;
子类TArticles:
TArticles = class(TKpModelViewControllerEntity) protected class var ResourceName: string; public constructor Create; override; procedure Manage; override; end; constructor TArticles.Create; begin inherited; ResourceName := 'articles/'; end; procedure TArticles.Manage; begin Writeln(ResourceName); end;
方案二:使用类字典统一管理静态值
基类维护一个字典,以子类类型为键,存储每个子类对应的ResourceName值。这种方式无需在子类重复声明字段,由基类统一管理所有子类的静态值。
代码示例
基类定义:
TKpModelViewControllerEntity = class private class var ResourceMap: TDictionary<TClass, string>; protected class function GetResourceName: string; class procedure SetResourceName(const AValue: string); public class constructor Create; class destructor Destroy; procedure Manage; end; class constructor TKpModelViewControllerEntity.Create; begin ResourceMap := TDictionary<TClass, string>.Create; end; class destructor TKpModelViewControllerEntity.Destroy; begin ResourceMap.Free; end; class function TKpModelViewControllerEntity.GetResourceName: string; begin // 根据当前类类型获取对应的值 ResourceMap.TryGetValue(Self.ClassType, Result); end; class procedure TKpModelViewControllerEntity.SetResourceName(const AValue: string); begin ResourceMap.AddOrSetValue(Self.ClassType, AValue); end; procedure TKpModelViewControllerEntity.Manage; begin Writeln(GetResourceName); // 获取当前子类对应的静态值 end;
子类初始化:
TCustomers = class(TKpModelViewControllerEntity) public class constructor Create; end; class constructor TCustomers.Create; begin inherited; SetResourceName('customers/'); end; TArticles = class(TKpModelViewControllerEntity) public class constructor Create; end; class constructor TArticles.Create; begin inherited; SetResourceName('articles/'); end;
方案对比
- 方案一:实现简单,每个子类拥有独立字段,但需要在子类中重写访问该字段的方法,否则基类方法会访问基类的共享字段。适合子类数量少、逻辑简单的场景。
- 方案二:无需子类重复声明字段,基类统一管理,扩展性更强,适合子类数量多或需要统一维护静态值的场景。
内容的提问来源于stack exchange,提问作者Marc Guillot
相关产品推荐
相关产品推荐

