Delphi中类重写的设计模式方案合理性咨询
Delphi多项目自定义项绘制方案的实践探讨
现有TFrame继承结构
TItemsFrame:定义带项的滚动区域的基础TFrameTDrawItemsFrame:继承自TItemsFrame,负责定义项的绘制方式TFullPage:继承自TDrawItemsFrame,新增页眉和页脚区域
遇到的问题
两个不同项目需要各自独特的项绘制逻辑,但不能修改TDrawItemsFrame的任何子类(如TFullPage、TOtherFullPage等)。
设想的解决方案
主项目代码结构
type TItemsFrame = Class(TFrame) type TDrawItemsFrame = Class(TItemsFrame) type TFullPage = Class({$I AncestorClass.inc}) type TOtherFullPage = Class({$I AncestorClass.inc}) // 其他同类型Frame定义
子项目差异化实现
- 项目A:定义
TCustom_A_DrawItemsFrame = Class(TDrawItemsFrame),将AncestorClass.inc内容设置为TCustom_A_DrawItemsFrame - 项目B:定义
TCustom_B_DrawItemsFrame = Class(TDrawItemsFrame),将AncestorClass.inc内容设置为TCustom_B_DrawItemsFrame
方案评估与替代策略
现有方案的合理性
你提出的通过.inc文件动态指定父类的方案,在Delphi中是可行的实践,尤其适合不修改原有子类代码的多项目差异化场景。这种方式利用Delphi编译包含机制,实现编译期父类替换,能快速适配不同项目的绘制需求。但需注意两点:
- 确保
AncestorClass.inc在各子项目中的唯一性,避免编译冲突 - 所有依赖该.inc的子类(如
TFullPage)必须与动态父类接口兼容,即TCustom_A_DrawItemsFrame和TCustom_B_DrawItemsFrame需完全继承TDrawItemsFrame的公开/保护接口,不能破坏原有子类的调用逻辑
策略模式的替代实现
若想实现更灵活的运行期绘制逻辑切换(而非编译期),可以用策略模式重构:
- 定义项绘制接口:
type IItemDrawer = interface ['{GUID}'] procedure DrawItem(ACanvas: TCanvas; ARect: TRect; AItemData: TObject); // 其他绘制相关方法 end;
- 修改
TDrawItemsFrame,引入接口依赖并替换原绘制逻辑:
type TDrawItemsFrame = Class(TItemsFrame) private FItemDrawer: IItemDrawer; public procedure SetItemDrawer(ADrawer: IItemDrawer); protected procedure DrawItem(ACanvas: TCanvas; ARect: TRect; AItemData: TObject); override; end; procedure TDrawItemsFrame.DrawItem(ACanvas: TCanvas; ARect: TRect; AItemData: TObject); begin if Assigned(FItemDrawer) then FItemDrawer.DrawItem(ACanvas, ARect, AItemData) else inherited; // 保留原有默认绘制逻辑 end;
- 各子项目实现专属绘制策略类:
// 项目A type TCustom_A_ItemDrawer = class(TInterfacedObject, IItemDrawer) procedure DrawItem(ACanvas: TCanvas; ARect: TRect; AItemData: TObject); end; // 项目B type TCustom_B_ItemDrawer = class(TInterfacedObject, IItemDrawer) procedure DrawItem(ACanvas: TCanvas; ARect: TRect; AItemData: TObject); end;
- 项目初始化时为Frame设置对应策略:
FullPageFrame.SetItemDrawer(TCustom_A_ItemDrawer.Create);
这种方式的优势:
- 无需修改原有类继承结构,完全遵循开闭原则
- 支持运行期切换绘制逻辑,灵活性更高
- 绘制逻辑与Frame类解耦,更易维护和扩展
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

