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

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.lryc.cn/news/615032.html

相关文章:

  • 《C++进阶之继承多态》【普通类/模板类的继承 + 父类子类的转换 + 继承的作用域 + 子类的默认成员函数】
  • Web3: 用ERC-1400革新公司股权激励
  • dokcer 容器里面安装vim 编辑器
  • 《软件测试与质量控制》实验报告五 功能自动化测试
  • 【Linux】Socket编程——UDP版
  • 第八章 SQL编程系列-Oracle慢SQL优化实战:从执行计划到索引设计的深度解析
  • UE蓝图节点Add Impulse和Add Torque in Radians
  • FMS 2025存储峰会获奖技术全景解读
  • 【线性代数】目录
  • 7、docker |其余命令
  • Datawhale+AI夏令营_让AI读懂财报PDF task2深入赛题笔记
  • RK3568笔记九十九:基于FFMPEG拉取RTSP流MPP硬解码视频显示
  • 使用Navicat备份数据库MySQL、PostGreSQL等
  • (一)React复习小满(userImmer/userMemo/useContext/userCallback/userRef)
  • 【SQL进阶】用EXPLAIN看透SQL执行计划:从“盲写“到“精准优化“
  • ABP VNext + Akka.NET:高并发处理与分布式计算
  • c++ opencv调用yolo onnx文件
  • 2025-08-09通过授权码的方式给exe程序充值
  • jQuery 零基础学习第一天
  • 计算BERT-BASE参数量
  • 【数据分享】各省农业土地流转率(2010-2023)
  • 安全合规3--防火墙
  • 光伏面板损伤检出率↑91%!陌讯多模态识别算法在无人机巡检的落地实践
  • 建筑物实例分割数据集-9,700 张图片 城市规划与发展 灾害评估与应急响应 房地产市场分析 智慧城市管理 地理信息系统(GIS) 环境影响评估
  • Android MVP架构详解:从理论到实践
  • leetcode2090:半径为K的子数组平均值(定长滑动窗口)
  • C# 使用iText获取PDF的trailer数据
  • 【lucene】HitsThresholdChecker命中阈值检测器
  • 【Datawhale AI夏令营第三期】多模态RAG
  • 《Learning To Count Everything》论文阅读