init
This commit is contained in:
276
docs/content/9-mixin-she-ji-mo-shi.md
Normal file
276
docs/content/9-mixin-she-ji-mo-shi.md
Normal file
@@ -0,0 +1,276 @@
|
||||
Mixin 设计模式是一种通过**多重继承**实现代码复用的技术,它将不同功能模块拆分为独立的可复用单元,并在运行时动态组合成完整的类实例。在 SunvStation 地理信息系统开发中,Mixin 模式被用于构建 SSProcessManager 核心类,将选择集管理、地理对象编辑、进度显示、日志记录和项目操作等功能模块化,实现了高度解耦和灵活复用的架构设计。该模式的核心优势在于:通过组合而非继承来扩展功能,避免了复杂的类层次结构,同时保持了代码的清晰性和可维护性。
|
||||
|
||||
## Mixin 架构概览
|
||||
|
||||
SunvStation 的 Mixin 架构采用**抽象基类(ABC)定义接口 + Mixin 类实现功能**的双重设计模式。每个功能领域都有对应的 `*Aware` 抽象基类定义契约,以及 `*Mixin` 实现类提供具体实现。SSProcessManager 作为最终的组合类,通过多重继承将所有 Mixin 组合成一个功能完整的管理器实例。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class SSProcessManager {
|
||||
+WorkSpace workspace
|
||||
+ScaleMap map
|
||||
+GlobalOptions global_options
|
||||
+ObjBaseAttr objBaseAttr
|
||||
+GeoBaseList selGeoList
|
||||
+GeoBaseList selNoteList
|
||||
+SSearchHelper searchHelper
|
||||
+GeoBase curSelGeo
|
||||
+StringArray curSelGeoFields
|
||||
+StringArray curSelGeoValues
|
||||
+GeoBaseList bufferObjList
|
||||
+list newBufferObjList
|
||||
+tuple curNewObj
|
||||
+bool enable_progress
|
||||
+Progress progress
|
||||
+Logger logger
|
||||
}
|
||||
|
||||
class LogAware {
|
||||
<<ABC>>
|
||||
+set_logger(Logger) abstract
|
||||
+log_error_msg(str) abstract
|
||||
}
|
||||
|
||||
class LogMixin {
|
||||
+Logger logger
|
||||
+set_logger(Logger)
|
||||
+log_error_msg(str)
|
||||
}
|
||||
|
||||
class ProgressAware {
|
||||
<<ABC>>
|
||||
+disable_progress() abstract
|
||||
+startProgress(str, int) abstract
|
||||
+stepProgress(str) abstract
|
||||
+closeProgress() abstract
|
||||
}
|
||||
|
||||
class ProgressMixin {
|
||||
+bool enable_progress
|
||||
+Progress progress
|
||||
+disable_progress()
|
||||
+startProgress(str, int)
|
||||
+stepProgress(str)
|
||||
+closeProgress()
|
||||
}
|
||||
|
||||
class GeoEditAware {
|
||||
<<ABC>>
|
||||
+createDefaultGeoBase(int, Dataset) abstract
|
||||
+getPolar(Point3D, Point3D) abstract
|
||||
+createNewObjByCode(int) abstract
|
||||
+addNewObjPoint(float, float, float, int, str) abstract
|
||||
+saveBufferObjToDatabase() abstract
|
||||
+updateRequest() abstract
|
||||
}
|
||||
|
||||
class GeoEditMixin {
|
||||
+createDefaultGeoBase(int, Dataset)
|
||||
+getPolar(Point3D, Point3D)
|
||||
+createNewObjByCode(int)
|
||||
+addNewObjPoint(float, float, float, int, str)
|
||||
+saveBufferObjToDatabase()
|
||||
+updateRequest()
|
||||
}
|
||||
|
||||
class ProjectMixin {
|
||||
+getWorkspace()
|
||||
+getCurrentMap()
|
||||
+pushUndoMark(str)
|
||||
+getSysPathName(int)
|
||||
+createMapFrame()
|
||||
+getLayerCount()
|
||||
+setLayerStatus(str, bool, int)
|
||||
}
|
||||
|
||||
class SelectionMixin {
|
||||
+clearSelection()
|
||||
+clearSelectCondition()
|
||||
+setSelectCondition(str, str, str)
|
||||
+selectFilter()
|
||||
+updateSysSelection(int)
|
||||
+getSysSelGeoList()
|
||||
+getSysSelNoteList()
|
||||
}
|
||||
|
||||
SSProcessManager --> LogMixin
|
||||
SSProcessManager --> ProgressMixin
|
||||
SSProcessManager --> GeoEditMixin
|
||||
SSProcessManager --> ProjectMixin
|
||||
SSProcessManager --> SelectionMixin
|
||||
|
||||
LogMixin ..|> LogAware
|
||||
ProgressMixin ..|> ProgressAware
|
||||
GeoEditMixin ..|> GeoEditAware
|
||||
SelectionMixin ..|> GeoEditAware
|
||||
SelectionMixin ..|> LogAware
|
||||
SelectionMixin ..|> ProgressAware
|
||||
```
|
||||
|
||||
这种架构设计的优势体现在三个方面:**接口隔离**确保每个 Mixin 只依赖必要的能力,**组合灵活性**允许按需选择功能模块,**类型安全**通过抽象基类强制实现契约。
|
||||
|
||||
Sources: [PySSProcess.py](PySSProcess.py#L18-L25), [log_mixin.py](ssprocess_mixins/log_mixin.py#L19-L22), [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L19-L26)
|
||||
|
||||
## Mixin 组合关系
|
||||
|
||||
SSProcessManager 通过多重继承组合五个 Mixin 类,继承顺序为 `SelectionMixin → GeoEditMixin → ProjectMixin → LogMixin → ProgressMixin`。这种顺序安排不是随意的,而是基于功能依赖关系精心设计的。SelectionMixin 依赖 GeoEditAware、LogAware 和 ProgressAware 接口,因此它继承了这些抽象基类但不提供实现;GeoEditMixin 依赖 LogAware 接口来记录错误;ProjectMixin 相对独立,主要提供工作空间和地图操作。最终的 SSProcessManager 通过继承所有 Mixin 实现类,获得完整的功能集合。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph 接口层
|
||||
LA[LogAware]
|
||||
PA[ProgressAware]
|
||||
GA[GeoEditAware]
|
||||
end
|
||||
|
||||
subgraph 实现层
|
||||
LM[LogMixin]
|
||||
PM[ProgressMixin]
|
||||
GM[GeoEditMixin]
|
||||
PJM[ProjectMixin]
|
||||
SM[SelectionMixin]
|
||||
end
|
||||
|
||||
subgraph 组合层
|
||||
SSM[SSProcessManager]
|
||||
end
|
||||
|
||||
LM -.实现.-> LA
|
||||
PM -.实现.-> PA
|
||||
GM -.实现.-> GA
|
||||
SM -.依赖.-> GA
|
||||
SM -.依赖.-> LA
|
||||
SM -.依赖.-> PA
|
||||
|
||||
SSM -.-> SM
|
||||
SSM -.-> GM
|
||||
SSM -.-> PJM
|
||||
SSM -.-> LM
|
||||
SSM -.-> PM
|
||||
|
||||
style SSM fill:#e1f5ff
|
||||
style SM fill:#fff4e1
|
||||
style GM fill:#fff4e1
|
||||
style PJM fill:#fff4e1
|
||||
style LM fill:#fff4e1
|
||||
style PM fill:#fff4e1
|
||||
```
|
||||
|
||||
这个组合结构体现了**功能分层**的设计思想:接口层定义契约,实现层提供具体功能,组合层将功能模块统一为可用的类实例。每个 Mixin 都是**独立可测试**的单元,可以单独开发和维护,而不需要关心其他 Mixin 的实现细节。
|
||||
|
||||
Sources: [PySSProcess.py](PySSProcess.py#L34), [selection_mixin.py](ssprocess_mixins/selection_mixin.py#L22-L25), [geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L40-L65)
|
||||
|
||||
## 功能模块详解
|
||||
|
||||
### 日志记录模块(LogMixin)
|
||||
|
||||
LogMixin 是最基础的功能模块,提供统一的日志记录接口。它实现 LogAware 抽象基类定义的两个方法:`set_logger()` 用于注入日志记录器实例,`log_error_msg()` 用于记录错误消息。该模块的设计遵循**依赖注入**原则,允许调用方提供自定义的 Logger 实现而非硬编码特定的日志框架。在 SSProcessManager 的 __init__ 方法中,logger 成员被初始化为 None,只有在调用者显式调用 `set_logger()` 后才激活日志功能。这种**延迟初始化**策略确保了 Mixin 的可选性和灵活性,不会因为某个功能未配置而阻止其他功能的使用。
|
||||
|
||||
Sources: [log_mixin.py](ssprocess_mixins/log_mixin.py#L26-L42), [PySSProcess.py](PySSProcess.py#L79)
|
||||
|
||||
### 进度显示模块(ProgressMixin)
|
||||
|
||||
ProgressMixin 管理进度条的显示和更新,提供了完整的进度反馈机制。该模块通过 `enable_progress` 布尔标志控制是否显示进度条,允许在批处理或非交互场景中禁用进度显示以提高性能。核心方法包括 `startProgress()` 初始化进度条、`stepProgress()` 更新进度、`closeProgress()` 关闭进度条,以及 `disable_progress()` 一次性禁用进度功能。ProgressMixin 内部使用来自 PySSWidget 模块的 Progress 类和辅助函数实现跨平台的进度显示,同时封装了异常处理逻辑,即使进度显示失败也不会影响主流程的正常执行。
|
||||
|
||||
Sources: [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L39-L80), [PySSProcess.py](PySSProcess.py#L78-L79)
|
||||
|
||||
### 地理编辑模块(GeoEditMixin)
|
||||
|
||||
GeoEditMixin 是最复杂的功能模块,提供了地理对象的创建、修改和保存等核心操作。该模块包含三十多个方法,涵盖了几何对象的完整生命周期管理。关键功能包括:`createDefaultGeoBase()` 根据类型创建点线面注记对象,`getPolar()` 和 `getPoint()` 进行坐标计算,`createNewObjByCode()` 和 `createNewObjByClass()` 通过编码或分类创建新对象,`addNewObjPoint()` 添加坐标点,`saveBufferObjToDatabase()` 将缓存对象批量保存到数据库。GeoEditMixin 还实现了复杂的对象打散功能(explodeNoteObject 和 explodeGeoObject),支持将组合对象分解为独立子对象,并在打散过程中保留或重置属性。
|
||||
|
||||
Sources: [geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L67-L200), [geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L760-L860)
|
||||
|
||||
### 项目管理模块(ProjectMixin)
|
||||
|
||||
ProjectMixin 提供工作空间和地图相关的高级操作,不依赖其他 Mixin 接口。主要功能包括:`getWorkspace()` 和 `getCurrentMap()` 获取当前工作空间和地图实例,`pushUndoMark()` 创建撤销标记以支持操作回滚,`getSysPathName()` 根据模式参数返回不同系统路径(配置、模板、脚本、临时文件等),`createMapFrame()` 和相关方法管理地图图框,`getLayerCount()`、`getLayerName()` 和 `setLayerStatus()` 进行图层操作。该模块还包含了 `_is_have_data()` 私有方法,用于检测指定多边形区域是否包含地理数据,这是一个辅助地理编辑的复杂空间查询功能。
|
||||
|
||||
Sources: [project_mixin.py](ssprocess_mixins/project_mixin.py#L28-L155), [project_mixin.py](ssprocess_mixins/project_mixin.py#L157-L267)
|
||||
|
||||
### 选择集管理模块(SelectionMixin)
|
||||
|
||||
SelectionMixin 负责选择集的管理和查询操作,它继承自 GeoEditAware、LogAware 和 ProgressAware,体现了 Mixin 之间的依赖关系。核心功能包括:`clearSelection()` 清除脚本选择集,`clearSelectCondition()` 清除选择条件,`setSelectCondition()` 设置复杂的选择条件(支持基本属性、几何特性和扩展属性),`selectFilter()` 执行过滤查询并更新选择集,`updateSysSelection()` 在脚本选择集和系统选择集之间同步数据。该模块通过集成 LogMixin 和 ProgressMixin,在选择过滤过程中自动记录错误和显示进度,展示了 Mixin 组合带来的**功能增强**效果。
|
||||
|
||||
Sources: [selection_mixin.py](ssprocess_mixins/selection_mixin.py#L22-L150)
|
||||
|
||||
## 共享状态管理
|
||||
|
||||
所有 Mixin 类共享一组核心实例变量,通过类型注解声明以确保类型安全和代码可读性。这些共享状态包括:工作空间实例(workspace)、地图实例(map)、全局选项(global_options)、基础属性管理器(objBaseAttr)、脚本选择集列表(selGeoList、selNoteList)、搜索助手(searchHelper)、缓存对象列表(bufferObjList、bufferNoteList、newBufferObjList、newBufferNoteList)、当前操作对象(curSelGeo、curNewObj)、删除缓冲区(delBufferGeoList)、进度控制标志(enable_progress)以及进度条和日志实例(progress、logger)。这种**共享状态设计**避免了参数在方法间传递的复杂性,但也要求 Mixin 之间有良好的协作约定,确保状态访问的线程安全和一致性。
|
||||
|
||||
Sources: [PySSProcess.py](PySSProcess.py#L36-L48), [selection_mixin.py](ssprocess_mixins/selection_mixin.py#L26-L40), [geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L67-L80)
|
||||
|
||||
## Mixin 模式对比
|
||||
|
||||
Mixin 设计模式与传统的设计模式在应用场景和实现方式上存在显著差异。下表对比了 Mixin 模式与几种常见模式在 SunvStation 架构中的应用特点:
|
||||
|
||||
| 模式类型 | 核心机制 | 代码复用方式 | 继承层次 | 适用场景 | SunvStation 应用 |
|
||||
|---------|---------|------------|---------|---------|----------------|
|
||||
| Mixin 模式 | 多重继承 | 水平组合 | 扁平化 | 功能模块化、可选特性 | 选择集、日志、进度、编辑、项目管理 |
|
||||
| 策略模式 | 组合+接口 | 算法替换 | 无继承 | 运行时行为变化 | 进度条实现策略(启用/禁用) |
|
||||
| 装饰器模式 | 包装+递归 | 动态增强 | 多层包装 | 功能动态叠加 | 暂未应用 |
|
||||
| 模板方法 | 继承+钩子 | 流程定制 | 单继承 | 算法骨架定义 | 对象打散流程(explodeObj 模板) |
|
||||
|
||||
Mixin 模式的独特优势在于它同时提供了**编译时类型安全**和**运行时组合灵活性**。与装饰器模式相比,Mixin 在组合时就确定了方法解析顺序(MRO),性能更好且更易于调试;与策略模式相比,Mixin 可以访问共享状态,更适合功能深度集成的场景。SunvStation 选择 Mixin 模式的主要原因包括:地理信息系统功能模块天然适合水平分类,SSProcessManager 需要同时支持多种操作且这些操作之间存在依赖关系,以及团队开发者熟悉 Python 的多重继承机制。
|
||||
|
||||
Sources: [geo_edit_mixin.py](ssprocess_mixins/geo_edit_mixin.py#L745-L770), [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L39-L55)
|
||||
|
||||
## 设计模式应用实例
|
||||
|
||||
选择集过滤流程是 Mixin 组合协同工作的典型实例。当用户调用 `selectFilter()` 执行选择集过滤时,多个 Mixin 的功能被无缝集成:
|
||||
|
||||
1. ProgressMixin 的 `startProgress()` 初始化进度条显示
|
||||
2. ProgressMixin 的 `stepProgress()` 显示"清理缓存"状态
|
||||
3. SelectionMixin 清空 `curSelGeoFields` 和 `curSelGeoValues` 缓存
|
||||
4. ProgressMixin 的 `stepProgress()` 显示"执行选择过滤"状态
|
||||
5. SelectionMixin 使用 `searchHelper` 根据条件过滤对象
|
||||
6. SelectionMixin 将过滤结果分类到 `selGeoList` 和 `selNoteList`
|
||||
7. ProgressMixin 的 `stepProgress()` 显示"更新选择集"状态
|
||||
8. ProgressMixin 的 `closeProgress()` 关闭进度条
|
||||
9. 如果过滤过程中发生错误,LogMixin 的 `log_error_msg()` 记录异常
|
||||
|
||||
整个流程中,SelectionMixin 提供核心业务逻辑,ProgressMixin 提供用户反馈,LogMixin 提供错误处理,三个 Mixin 通过共享状态协同工作,无需显式传递参数或调用链。这种**协作式设计**使得复杂的业务流程被分解为清晰的关注点,每个 Mixin 只负责自己的职责,代码易于理解和维护。
|
||||
|
||||
Sources: [selection_mixin.py](ssprocess_mixins/selection_mixin.py#L96-L125)
|
||||
|
||||
## 扩展与定制
|
||||
|
||||
Mixin 模式的另一个重要优势在于支持**功能扩展和定制**。开发者可以通过以下方式扩展 SSProcessManager 的功能:
|
||||
|
||||
1. **新增 Mixin 类**:创建新的 `*Mixin` 类实现特定功能,如 `DataExportMixin` 负责数据导出,或 `ValidationMixin` 负责数据验证。新增 Mixin 需要继承相关的 `*Aware` 接口以确保类型安全。
|
||||
|
||||
2. **覆盖现有方法**:创建 SSProcessManager 的子类,覆盖特定 Mixin 方法以修改行为。例如,可以覆盖 `log_error_msg()` 方法,不仅记录日志还弹窗提示用户。
|
||||
|
||||
3. **组合现有 Mixin**:创建新的管理器类,只继承需要的 Mixin。例如,创建一个只包含日志和进度功能的轻量级管理器,用于不需要地理编辑的脚本场景。
|
||||
|
||||
4. **自定义 Logger 和 Progress 实现**:通过 `set_logger()` 和 `enable_progress` 接口,注入自定义的日志记录器和进度显示实现,实现与企业系统的集成。
|
||||
|
||||
扩展时需要遵循的原则包括:保持 Mixin 的**单一职责**,避免让一个 Mixin 做太多事情;确保共享状态的**一致性约定**,防止不同 Mixin 之间的状态冲突;提供**合理的默认实现**,使 Mixin 在没有依赖项时也能工作(如 LogMixin 在 logger 为 None 时不崩溃)。
|
||||
|
||||
Sources: [log_mixin.py](ssprocess_mixins/log_mixin.py#L37-L42), [PySSProcess.py](PySSProcess.py#L34)
|
||||
|
||||
## 最佳实践与注意事项
|
||||
|
||||
在使用 Mixin 设计模式时,需要遵循以下最佳实践以确保代码质量:
|
||||
|
||||
1. **优先使用抽象基类定义接口**:每个功能领域都应该有对应的 `*Aware` 抽象基类,明确定义契约。这提供了编译时类型检查,帮助开发者理解 Mixin 之间的依赖关系。
|
||||
|
||||
2. **控制继承深度和宽度**:虽然 Mixin 支持多重继承,但应该避免过深的继承层次(超过 3 层)和过宽的继承宽度(超过 7 个 Mixin)。SunvStation 的 SSProcessManager 继承了 5 个 Mixin,处于合理范围内。
|
||||
|
||||
3. **避免钻石继承问题**:当多个 Mixin 继承同一个基类时,需要理解 Python 的方法解析顺序(MRO)。SunvStation 通过让 SelectionMixin 继承多个 `*Aware` 接口但不提供实现,而由 SSProcessManager 继承具体的 Mixin 实现类,避免了复杂的继承冲突。
|
||||
|
||||
4. **明确共享状态的读写权限**:共享状态虽然简化了代码,但也带来了耦合。应该通过文档明确哪些状态是只读的,哪些可以修改,以及在什么生命周期阶段访问是安全的。
|
||||
|
||||
5. **提供可选功能的开关机制**:不是所有 Mixin 功能在所有场景下都需要。像 ProgressMixin 的 `enable_progress` 标志这样的开关机制,允许调用方根据场景选择是否启用某个功能。
|
||||
|
||||
Sources: [selection_mixin.py](ssprocess_mixins/selection_mixin.py#L22-L40), [progress_mixin.py](ssprocess_mixins/progress_mixin.py#L39-L52), [PySSProcess.py](PySSProcess.py#L34)
|
||||
|
||||
## 相关文档
|
||||
|
||||
Mixin 设计模式是 SunvStation 架构的核心组成部分,与其他设计模式和功能模块密切相关。如需深入了解相关概念,建议按以下顺序阅读:
|
||||
|
||||
- [SunvStation 系统架构](6-sunvstation-xi-tong-jia-gou) 了解 SSProcessManager 在整体架构中的位置和职责
|
||||
- [使用 SSProcess 管理选择集](4-shi-yong-ssprocess-guan-li-xuan-ze-ji) 掌握 SelectionMixin 提供的选择集操作
|
||||
- [配置日志记录器](37-pei-zhi-ri-zhi-ji-lu-qi) 学习 LogMixin 的实际应用
|
||||
- [进度条使用指南](38-jin-du-tiao-shi-yong-zhi-nan) 探索 ProgressMixin 的进阶用法
|
||||
- [SSProcessManager 完整 API](40-ssprocessmanager-wan-zheng-api) 查看所有 Mixin 方法的详细说明
|
||||
|
||||
通过理解 Mixin 设计模式,开发者可以更好地扩展和定制 SunvStation 的功能,构建高效、可维护的地理信息系统脚本。
|
||||
Reference in New Issue
Block a user