You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi中类重写的设计模式方案合理性咨询

Delphi多项目自定义项绘制方案的实践探讨

现有TFrame继承结构

  • TItemsFrame:定义带项的滚动区域的基础TFrame
  • TDrawItemsFrame:继承自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的公开/保护接口,不能破坏原有子类的调用逻辑

策略模式的替代实现

若想实现更灵活的运行期绘制逻辑切换(而非编译期),可以用策略模式重构:

  1. 定义项绘制接口:
type
  IItemDrawer = interface
    ['{GUID}']
    procedure DrawItem(ACanvas: TCanvas; ARect: TRect; AItemData: TObject);
    // 其他绘制相关方法
  end;
  1. 修改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;
  1. 各子项目实现专属绘制策略类:
// 项目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;
  1. 项目初始化时为Frame设置对应策略:
FullPageFrame.SetItemDrawer(TCustom_A_ItemDrawer.Create);

这种方式的优势:

  • 无需修改原有类继承结构,完全遵循开闭原则
  • 支持运行期切换绘制逻辑,灵活性更高
  • 绘制逻辑与Frame类解耦,更易维护和扩展

内容的提问来源于stack exchange,提问作者zeus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 18:33:09