Files
coco df489d5640 a
2026-07-03 16:05:30 +08:00

15 KiB
Raw Permalink Blame History

工厂模式

**本文引用的文件** - [ProManager.cpp](file://cpp/Managers/ProManager.cpp) - [ProManager.h](file://h/ProManager.h) - [HandleProcessor.h](file://h/HandleProcessor.h) - [LinkList.h](file://h/LinkList.h) - [DataMngStruct.h](file://h/DataMngStruct.h) - [Project.h](file://h/Project.h) - [TestingZone.h](file://h/TestingZone.h) - [Constant.h](file://h/Constant.h) - [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)

目录

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

引言

本文件围绕 CProManager::GetDMS() 方法展开,系统性解析其作为“工厂模式”的具体实现:如何依据传入的句柄(DWORD dwHandle)在内部链表 m_dmsLinkList 中查找并返回相应的 CDataMngStruct 派生对象;如何通过类型识别逻辑(句柄风格)动态创建对象;以及对象生命周期控制与缓存复用策略。同时结合实际调用场景,说明该工厂模式如何实现管理对象的动态创建与解耦,提升系统的可扩展性与可维护性,并给出在“项目管理”与“测区管理”中的具体应用路径。

项目结构

与工厂模式直接相关的核心模块与文件如下:

  • 管理器层:CProManager 负责数据管理对象的工厂与缓存
  • 句柄处理器:CHandleProcessor 提供句柄解析与生成能力
  • 链表容器:CLinkList 模板类提供按句柄索引的对象缓存
  • 抽象基类:CDataMngStruct 定义统一接口
  • 具体派生类:CProject、CTestingZone 分别代表“项目”和“测区”
  • 常量定义:PZ_STYLE_* 标识不同对象类型
  • 使用方:CDataOperator 在视图交互中调用 GetDMS 获取对象并展示详情
graph TB
subgraph "管理器层"
PM["CProManager<br/>工厂与缓存"]
end
subgraph "句柄处理"
HP["CHandleProcessor<br/>解析/生成句柄"]
end
subgraph "容器"
LL["CLinkList&lt;CDataMngStruct*&gt;<br/>按句柄缓存"]
end
subgraph "抽象与派生"
DMS["CDataMngStruct<br/>抽象接口"]
PRJ["CProject<br/>项目"]
TZ["CTestingZone<br/>测区"]
end
subgraph "常量"
CST["Constant.h<br/>PZ_STYLE_*"]
end
subgraph "使用方"
DO["CDataOperator<br/>调用GetDMS"]
end
PM --> HP
PM --> LL
PM --> DMS
DMS --> PRJ
DMS --> TZ
PM --> CST
DO --> PM

图表来源

章节来源

核心组件

  • CProManager::GetDMS:工厂入口,负责根据句柄风格创建或复用对象,并通过链表缓存返回
  • CHandleProcessor:从句柄中提取类型(style)与标识(ID),并支持生成新句柄
  • CLinkList:模板链表,以句柄为键存储对象指针,提供查找、添加、删除等操作
  • CDataMngStruct:抽象基类,定义统一的展示接口
  • CProject、CTestingZone:具体派生类,分别对应“项目”和“测区”,构造时携带数据库连接与ID
  • PZ_STYLE_*:类型枚举,用于区分不同管理对象类型

章节来源

架构总览

CProManager::GetDMS 的工作流如下:

  • 从句柄中解析类型(style)与ID
  • 在 m_dmsLinkList 中按句柄查找对象
  • 若未命中,则根据 style 创建相应派生类对象(如 CProject 或 CTestingZone
  • 将新对象加入缓存链表后返回
  • 调用方通过返回的 CDataMngStruct* 调用统一接口(如 ShowDetailInfo
sequenceDiagram
participant Caller as "调用方"
participant PM as "CProManager"
participant HP as "CHandleProcessor"
participant LL as "CLinkList"
participant PRJ as "CProject"
participant TZ as "CTestingZone"
Caller->>PM : GetDMS(dwHandle)
PM->>HP : GetStyleFromHandle(dwHandle)
PM->>LL : Get(dwHandle)
alt 未命中缓存
PM->>HP : GetIDFromHandle(dwHandle)
PM->>PM : switch(style)
opt style==PZ_STYLE_PRO
PM->>PRJ : new CProject(ID, Connection)
end
opt style==PZ_STYLE_TZ
PM->>TZ : new CTestingZone(ID, Connection)
end
PM->>LL : Add(dwHandle, pDMS)
end
PM-->>Caller : 返回 pDMS

图表来源

详细组件分析

CProManager::GetDMS 工厂实现

  • 输入:DWORD dwHandle
  • 关键步骤:
    • 解析类型:uStyle = m_handleProcessor.GetStyleFromHandle(dwHandle)
    • 查找缓存:pDMS = m_dmsLinkList.Get(dwHandle)
    • 未命中则创建:根据 uStyle 创建 CProject 或 CTestingZone,构造参数包含 dwID 与数据库连接
    • 加入缓存:m_dmsLinkList.Add(dwHandle, pDMS)
    • 返回对象指针
  • 类型识别:依赖 PZ_STYLE_PRO、PZ_STYLE_TZ 常量
  • 缓存策略:按句柄键值缓存,避免重复创建,提升访问性能
flowchart TD
Start(["函数入口"]) --> ParseStyle["解析句柄类型(style)"]
ParseStyle --> Lookup["按句柄查找缓存"]
Lookup --> Found{"缓存命中?"}
Found --> |是| ReturnCached["返回缓存对象"]
Found --> |否| ParseID["解析ID(GetIDFromHandle)"]
ParseID --> SwitchStyle{"style分支"}
SwitchStyle --> |PZ_STYLE_PRO| NewProj["new CProject(ID, Connection)"]
SwitchStyle --> |PZ_STYLE_TZ| NewTZ["new CTestingZone(ID, Connection)"]
SwitchStyle --> |其他| Noop["不创建(保持空指针)"]
NewProj --> AddCache["加入缓存Add(dwHandle, pDMS)"]
NewTZ --> AddCache
Noop --> AddCache
AddCache --> ReturnObj["返回对象指针"]
ReturnCached --> End(["函数退出"])
ReturnObj --> End

图表来源

章节来源

对象生命周期与缓存管理

  • 生命周期控制:
    • 构造:CProManager 构造时清空缓存
    • 销毁:CProManager 析构时遍历并 delete 缓存中的对象,随后清空链表
    • 删除:提供 DeleteObjInMem(dwHandle) 用于显式删除缓存对象
  • 缓存一致性:
    • CLinkList::Add 在添加前会检查重复(相同句柄或同一对象),避免重复
    • CLinkList::Delete 支持按句柄或对象删除
  • 作用:减少频繁创建销毁带来的开销,提升 UI 列表与详情展示的响应速度
classDiagram
class CProManager {
+GetDMS(dwHandle) CDataMngStruct*
+DeleteObjInMem(dwHandle) void
-m_dmsLinkList : CLinkList<CDataMngStruct*>
-m_handleProcessor : CHandleProcessor
}
class CHandleProcessor {
+GetStyleFromHandle(dwHandle) UINT
+GetIDFromHandle(dwHandle) DWORD
+GenerateHandle(dwID, uStyle) DWORD
}
class CLinkList~CDataMngStruct*~ {
+Get(dwHandle) CDataMngStruct*
+Add(dwHandle, data) bool
+Delete(dwHandle) bool
+DeleteAll() void
}
class CDataMngStruct {
<<abstract>>
+ShowDetailInfo(list) bool
}
class CProject {
+ShowDetailInfo(list) bool
-m_dwID : DWORD
}
class CTestingZone {
+ShowDetailInfo(list) bool
-m_dwID : DWORD
}
CProManager --> CHandleProcessor : "使用"
CProManager --> CLinkList : "缓存"
CDataMngStruct <|-- CProject
CDataMngStruct <|-- CTestingZone

图表来源

章节来源

类型识别与扩展点

  • 类型识别:通过 CHandleProcessor::GetStyleFromHandle 从句柄中提取 style,再在工厂中 switch 分支创建对应对象
  • 扩展方式:新增类型只需在 switch 中添加新分支,并确保对应派生类已实现构造签名(ID, Connection
  • 常量来源:PZ_STYLE_PRO、PZ_STYLE_TZ 等常量定义于 Constant.h

章节来源

实际调用场景与解耦效果

  • 项目详情展示:CDataOperator::ShowProjectInfo 通过 GetDMS(dwProHandle) 获取 CProject 对象,调用其 ShowDetailInfo 展示项目信息,并联动测试数据列表
  • 测区详情展示:CDataOperator::ShowTzInfo 通过 GetDMS(dwTzHandle) 获取 CTestingZone 对象,调用其 ShowDetailInfo 展示测区信息,并联动测试数据列表
  • 解耦优势:
    • 视图层仅依赖抽象接口(CDataMngStruct::ShowDetailInfo),不关心具体类型
    • 工厂负责类型识别与对象创建,便于扩展新的管理对象类型
    • 通过缓存降低重复创建成本,提升交互流畅度
sequenceDiagram
participant View as "视图/控制器"
participant DO as "CDataOperator"
participant PM as "CProManager"
participant DMS as "CDataMngStruct*"
participant PRJ as "CProject"
participant TZ as "CTestingZone"
View->>DO : 请求展示项目详情
DO->>PM : GetDMS(dwProHandle)
PM-->>DO : 返回 CDataMngStruct*
DO->>DMS : ShowDetailInfo(...)
alt 是项目
DMS-->>PRJ : 动态转换/调用
else 是测区
DMS-->>TZ : 动态转换/调用
end
DO->>PM : GetDMS(dwTzHandle)
PM-->>DO : 返回 CDataMngStruct*
DO->>DMS : ShowDetailInfo(...)

图表来源

章节来源

依赖关系分析

  • 组件耦合:
    • CProManager 依赖 CHandleProcessor(解析句柄)、CLinkList(缓存)、CDataMngStruct(抽象基类)
    • 具体派生类(CProject、CTestingZone)依赖数据库连接与ID,但对调用方透明
  • 外部依赖:
    • 数据库连接(_ConnectionPtr)贯穿对象构造,用于数据加载与持久化
  • 循环依赖:
    • 无直接循环依赖;工厂仅单向依赖句柄处理器与链表容器
graph LR
PM["CProManager"] --> HP["CHandleProcessor"]
PM --> LL["CLinkList<CDataMngStruct*>"]
PM --> DMS["CDataMngStruct"]
DMS --> PRJ["CProject"]
DMS --> TZ["CTestingZone"]
PM --> CST["Constant.h(PZ_STYLE_*)"]

图表来源

章节来源

性能考量

  • 时间复杂度:
    • 缓存命中:O(1)
    • 缓存未命中:O(n)(链表查找),n 为缓存长度
  • 空间复杂度:O(n),n 为已创建对象数
  • 优化建议:
    • 优先保证高频访问对象的缓存命中率(例如项目/测区列表页)
    • 控制缓存规模,必要时提供清理策略(如 DeleteObjInMem
    • 对链表查找进行优化(如引入哈希映射)以降低查找成本

[本节为通用性能讨论,无需列出具体文件来源]

故障排查指南

  • 常见问题与定位:
    • 句柄无效或类型未知:GetStyleFromHandle 返回异常值,导致 switch 未匹配,返回空指针
    • 缓存未命中但创建失败:检查构造参数(ID、Connection)是否有效
    • 内存泄漏:确认析构时是否正确 delete 缓存对象
  • 排查要点:
    • 核对句柄生成与解析流程(GenerateHandle vs GetStyleFromHandle/GetIDFromHandle
    • 检查链表 Add/Delete 行为,避免重复添加或遗漏删除
    • 在调用方处对返回对象判空后再调用接口

章节来源

结论

CProManager::GetDMS 通过“工厂模式+缓存”的组合,实现了对 CDataMngStruct 派生对象的统一创建与管理。其关键价值在于:

  • 类型识别与动态创建:基于句柄风格在运行时选择具体类型
  • 缓存复用:显著降低对象创建成本,提升交互性能
  • 接口解耦:调用方仅依赖抽象接口,便于扩展新的管理对象类型
  • 生命周期可控:构造/析构与显式删除接口配合,保障资源释放

在“项目管理”与“测区管理”场景中,该工厂模式使视图层能够以一致的方式获取并展示对象详情,同时为后续扩展更多管理对象类型提供了清晰的扩展点与稳定的契约。

[本节为总结性内容,无需列出具体文件来源]

附录

[本节为补充说明,无需列出具体文件来源]