当前位置: 首页 > ds >正文

Delphi:TList/TObjectList 设计中的 Notify 设计范式

在 Delphi 的 TList/TObjectList 设计中,Notify 方法实现了经典的 观察者模式(Observer Pattern)模板方法模式(Template Method Pattern) 的混合设计,下面是详细解析:


🔍 设计模式分析:复合型模式实现

1. 观察者模式(Observer Pattern)
  • 核心思想:对象(Subject)状态变化时自动通知依赖对象(Observers)

  • Notify 中的体现

    // TList (Subject) 内部操作流程
    procedure TList.Delete(Index: Integer);
    beginItem := Get(Index);          // 获取要删除的元素Notify(Item, lnDeleted);     // ✅ 发送删除通知InternalDelete(Index);       // 实际执行删除
    end;
    
    • TList 作为 Subject(主题),在状态变更(元素删除)时主动调用 Notify
    • TObjectList 作为 Observer(观察者),通过覆盖 Notify 实现响应逻辑
2. 模板方法模式(Template Method Pattern)
  • 核心思想:父类定义算法骨架,子类重写特定步骤

  • 在继承链中的实现

    «abstract»
    TList
    +Notify(Ptr, Action) : virtual
    #Delete(Index)
    #Insert()
    #Clear()
    TObjectList
    +Notify(Ptr, Action) : override
    • 模板方法TList.Delete/Insert/Clear 包含固定流程(算法骨架)
    • 扩展点Notify 是预设的扩展钩子(hook),子类可定制行为
    • 控制反转TList 控制流程,TObjectList 控制具体释放行为

⚙️ Notify 机制执行流程

UserTListTObjectListStoredObjectDelete(Index)获取元素指针 PtrNotify(Ptr, lnDeleted)TObject(Ptr).Freealt[OwnsObjects 且Action=lnDeleted]inherited Notify // 基类处理执行实际删除操作UserTListTObjectListStoredObject

💡 设计优势分析

1. 开闭原则(OCP)
  • 对扩展开放:通过覆盖 Notify,可添加自定义行为
    typeTLoggingObjectList = class(TObjectList)protectedprocedure Notify(Ptr: Pointer; Action: TListNotification); override;end;procedure TLoggingObjectList.Notify(...);
    beginif Action = lnAdded thenLog('添加对象: ' + TObject(Ptr).ClassName);inherited; // 保持核心释放行为
    end;
    
  • 对修改封闭TList 的核心算法永不改变
2. 单一职责原则(SRP)
职责
TList管理集合数据结构(增删改查)
TObjectList管理对象生命周期(仅通过 Notify 扩展)
3. 控制反转(IoC)
// 基类控制流程
procedure TList.Clear;
beginwhile Count > 0 doDelete(Count - 1); // ➡️ 触发 Notify 调用
end;

子类不关心何时被调用,只专注 “当删除发生时该做什么”


⚠️ 关键设计决策

  1. 双向通讯机制

    • 父类调用子类:TList.DeleteTObjectList.Notify
    • 子类回调父类:inherited Notify() 保持扩展性
  2. 按事件类型分发

    TListNotification = (lnAdded, lnExtracted, lnDeleted);
    

    不同的操作(Add/Delete/Extract)触发不同事件类型,实现精细控制

  3. 条件触发设计

    if OwnsObjects and (Action = lnDeleted) then ...
    

    通过布尔开关控制行为,避免资源管理冲突


🔥 对比原始设计差异

您给出的原始代码与现实中的 Delphi 实现略有不同:

实际 Delphi 实现(更严谨):
procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin// 仅在删除且拥有所有权时释放if (Action = lnDeleted) and FOwnsObjects thenTObject(Ptr).Free;// 关键:先处理再传递通知(避免父类操作已释放对象)inherited Notify(Ptr, Action);
end;
您提供代码的潜在风险:
// 错误顺序示例(您的代码):
beginif OwnsObjects then ... Free;  // 先释放对象inherited Notify;              // ⚠️ 父类可能操作已释放的内存
end;

🌟 总结:Notify 设计范式

  1. 模式类型观察者模式(事件通知)+ 模板方法模式(可扩展算法框架)
  2. 设计目的:实现对象生命周期管理的正交扩展
  3. 行业应用
    • Delphi/C++ Builder 的 VCL/RTL 容器类
    • Qt 的 QObject 事件系统
    • .NET Collection<T> 的虚方法保护
  4. 黄金法则

    “当需要扩展行为但不破坏封装时,用事件钩子代替直接修改”
    —— 《设计模式:可复用面向对象软件的基础》

http://www.xdnf.cn/news/17541.html

相关文章:

  • 供应链需求预测项目如何设定合理的KPI、准确率指标(十四)
  • Spring Boot 集成 Quartz 实现定时任务(Cron 表达式示例)
  • Spark02 - SparkContext介绍
  • 【多模态目标检测数据集】【VEDAI】航空影像中的车辆检测:小目标检测基准
  • 2025年渗透测试面试题总结-10(题目+回答)
  • C语言:构造类型
  • C++学习之STL学习:map/set
  • 【面试题】cookie和session 的区别
  • 使用GTX ip core + SDI IP core实现SDI设计
  • BeanDefinition 与 Bean 生命周期(面试高频考点)
  • 《Learning To Count Everything》论文阅读
  • 鸿蒙开发中的Tabs组件详解
  • 使用 Visual Studio 2022 编译 PortAudio 项目
  • docker基础前置
  • Microsoft Office Visio(流程图)学习笔记
  • 【华为仓颉编程语言】标识符
  • 栈和队列应用实操
  • LabVIEW核物理虚拟仪器教学
  • 【26】C#实战篇—— 多个线程函数对同一个 Excel 文件进行写操作引起的文件冲突问题,解决方法
  • Playwright C# 自动登录并上传 Excel 文件 的可运行示例
  • 十九、MySQL-DQL-基本查询
  • Python day39
  • Linux系统之lua 详解
  • 一周学会Matplotlib3 Python 数据可视化-标注 (Annotations)
  • 【线性代数】6二次型
  • Windows设置英文路径显示为中文名称的文件夹
  • Android 设置/修改系统NTP服务地址
  • Golang的本地缓存freecache
  • Nginx 功能扩展与二次开发实践
  • HUAWEI交换机命令基础