当前位置: 首页 > 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.dtcms.com/a/323097.html

相关文章:

  • Day38--动态规划--322. 零钱兑换,279. 完全平方数,139. 单词拆分,56. 携带矿石资源(卡码网),背包问题总结
  • 10 分钟用 FastAPI 将机器学习模型上线为 REST API
  • day28 IPC通信机制
  • C++隐式转换的魔法与陷阱:explicit关键字的救赎
  • RecyclerView 缓存机制
  • centos 怎么将一些命令设置为快捷命令
  • 2025华数杯数学建模C题:可调控生物节律LED光源全解析
  • LLM表征的提取方式
  • 【Python 高频 API 速学 ⑥】
  • 【Mac】MLX:Lora微调工作流
  • 【排序算法】①直接插入排序
  • QT第二讲-信号和槽
  • uniapp实现的圆形滚盘组件模板
  • ThingsBoard配置邮件发送保姆级教程(新版qq邮箱)
  • SkyWalking-2--Java Agent是什么?
  • Qt与嵌入式设备中的字节序问题
  • 客服Agent革命:智能客服系统的技术实现与效果评估
  • 八、《DaaS(设备即服务):企业轻资产化新路径》--从97.4%首期投入削减到AI算力高效迭代的范式革命
  • ​​​​​​​【Datawhale AI夏令营】多模态RAG财报问答挑战赛:学习笔记与上分思考
  • “黑影御剑飞行”视频引发的思考
  • 差分放大电路的四种接法
  • react-window
  • 组合期权:垂直价差
  • Playwright C# 自动登录并上传 Excel 文件 的可运行示例
  • Java 数据类型与内存模型:从字节到引用的底层逻辑
  • 数字图像处理基础——opencv库(Python)
  • C语言库中的字符函数
  • 基于 RAUC 的 Jetson OTA 升级全攻略
  • Vue和Springboot初步前后端分离建立项目连接(解决前后端跨域问题)
  • linux安装php