之后将类添加到类中

Dan*_*all 11 delphi oop model-view-controller interface

是否有可能加入和实施一个已经存在的类(这是一个后代的接口TInterfacedTInterfacedPersistent)来完成分离模型和视图到2个单位?

一个小小的解释为什么我需要这样的东西:

我正在开发一个树形结构,开放式模型,它具有以下结构(非常简化和不完整,只是为了说明问题的轮廓):

Database_Kernel.pas

TVMDNode = class(TInterfacedPersistent);
public
  class function ClassGUID: TGUID; virtual; abstract; // constant. used for RTTI

  property RawData: TBytes {...};
  constructor Create(ARawData: TBytes);

  function GetParent: TVMDNode;
  function GetChildNodes: TList<TVMDNode>;
end;
Run Code Online (Sandbox Code Playgroud)

Vendor_Specific_Stuff.pas

TImageNode = class(TVMDNode)
public
  class function ClassGUID: TGUID; override; // constant. used for RTTI

  // Will be interpreted out of the raw binary data of the inherited class
  property Image: TImage {...};
end;

TUTF8Node = class(TVMDNode)
public
  class function ClassGUID: TGUID; override; // constant. used for RTTI

  // Will be interpreted out of the raw binary data of the inherited class
  property StringContent: WideString {...};
end;

TContactNode = class(TVMDNode)
public
  class function ClassGUID: TGUID; override; // constant. used for RTTI

  // Will be interpreted out of the raw binary data of the inherited class
  property PreName: WideString {...};
  property FamilyName: WideString {...};
  property Address: WideString {...};
  property Birthday: TDate {...};
end;
Run Code Online (Sandbox Code Playgroud)

使用基于GUID的RTTI(使用ClassGUID),该函数GetChildNodes能够找到匹配的类并使用原始数据初始化它.(每个数据集包含ClassGUIDRawData旁像创建/更新时间戳其他数据)

重要的是要注意我的API(Database_Kernel.pas)与供应商的节点类(Vendor_Specific_Stuff.pas)严格分开.


供应商特定程序的GUI希望可视化节点,例如为它们提供用户友好的名称,图标等.

以下想法有效:

IGraphicNode = interface(IInterface)
  function Visible: boolean;
  function Icon: TIcon;
  function UserFriendlyName: string;
end;
Run Code Online (Sandbox Code Playgroud)

供应商的具体后裔TVMDNodeVendor_Specific_Stuff.pas将实现IGraphicNode接口.

但供应商还需要更改Database_Kernel.pas以实现IGraphicNode基本节点类TVMDNode(用于"未知"节点,其中RTTI无法找到数据集的匹配类,因此至少可以使用读取二进制原始数据TVMDNode.RawData).

所以他将改变我的课程如下:

TVMDNode = class(TInterfacedPersistent, IGraphicNode);
public
  property RawData: TBytes {...};
  class function ClassGUID: TGUID; virtual; abstract; // constant. used for RTTI
  constructor Create(ARawData: TBytes);
  function GetParent: TVMDNode;
  function GetChildNodes: TList<TVMDNode>;

  // --- IGraphicNode
  function Visible: boolean; virtual; // default behavior for unknown nodes: False
  function Icon: TIcon; virtual; // default behavior for unknown nodes: "?" icon
  function UserfriendlyName: string; virtual; // default behavior for unknown nodes: "Unknown"
end;
Run Code Online (Sandbox Code Playgroud)

问题是IGraphicNode供应商/程序特定的,不应该在API中Database_Kernel.pas,因为GUI和Model/API应该严格划分.

我的愿望是可以在一个单独的单元中将interace IGraphicNode添加到现有TVMDNode类(它已经是TInterfacedPersistent允许接口的后代)中.据我所知,Delphi不支持这样的东西.

旁边的事实,这是不是很好混在一个单元/类模型和视图,将有下列实际问题:如果供应商必须改变我的Database_Kernel.pasAPI来扩展TVMDNodeIGraphicNode接口,他需要重新做所有他的更改,一发布我的API的新版本Database_Kernel.pas.

我该怎么办?我想很长时间用Delphi的OOP可能的解决方案.解决方法可能是将TVMDNode嵌套到一个容器类中,该容器类具有辅助RTTI,因此在找到TVMDNode该类之后,我可以搜索一个TVMDNodeGUIContainer类.但这听起来很扼杀,就像一个肮脏的黑客.

PS:这个API是一个OpenSource/GPL项目.我试图保持与旧代Delphi(例如6)的兼容,因为我想最大化可能的用户数量.但是,如果只能使用新一代Delphi语言解决上述问题,我可能会考虑删除Delphi 6对此API的支持.

xmo*_*jmr 1

如果您应用工厂设计模式,您可以保留保留数据并通过继承实现它的能力,并且仍然为存储在表中的 ClassGUID 创建正确的实例。

对于每个节点类,都有一个类工厂(或只是一个函数指针)负责创建正确的 Delphi 类。类工厂可以在内核单例对象的单元初始化部分中注册自己(每次应用程序启动一次)。

然后,内核单例会将 GUID 映射到正确的工厂,该工厂又会调用正确的类实例构造函数(如http://delphipatterns.blog.com/2011/03/23/abstract-factory所示)

包可以分为单独的 DLL 和在单独单元中实现的类,但仍然继承自一个基本 TVMNode 类。

您现在使用 RTTI 实现的功能可以通过一些虚拟方法轻松地在后代类或工厂类中得到支持。

您还可以考虑使用更简单的数据传输对象来保存/加载 TVMNode,并且可能从已经很好理解的对象关系映射器对象持久性框架中获得一些灵感,因为您试图解决的问题在我看来就像它们所面临的问题一样处理(已经)

我不知道这个类的Delphi开源框架有什么好的。但对于其他语言,您可以查看Java HibernateMicrosoft .NET Entity Framework或简约的Google Protocol Buffers 序列化器

在此输入图像描述