组件扁平化分析Skill component-flattening-analysis

这个技能用于分析和优化软件组件的层次结构,识别并修复根命名空间中的孤儿类,通过扁平化组件层级提高代码可维护性和清晰度。关键词包括:组件扁平化、孤儿类、代码重构、软件架构、命名空间优化、层次结构修复。

架构设计 0 次安装 0 次浏览 更新于 3/15/2026

名称: 组件扁平化分析 描述: 通过检测根命名空间中的孤儿类并确保组件仅作为叶子节点,识别并修复组件层次结构问题。使用场景包括分析组件结构、查找孤儿类、扁平化组件层次结构、移除组件嵌套,或当用户询问组件扁平化、孤儿类或组件结构清理时。

组件扁平化分析

这个技能识别组件层次结构问题,并确保组件在目录/命名空间结构中仅作为叶子节点存在,移除根命名空间中的孤儿类。

如何使用

快速开始

请求分析您的代码库:

  • “查找根命名空间中的孤儿类”
  • “扁平化组件层次结构”
  • “识别需要扁平化的组件”
  • “分析组件结构以查找层次结构问题”

使用示例

示例1:查找孤儿类

用户:“查找根命名空间中的孤儿类”

技能将:
1. 扫描组件命名空间以查找层次结构问题
2. 识别根命名空间中的孤儿类
3. 检测基于其他组件构建的组件
4. 建议扁平化策略
5. 创建重构计划

示例2:扁平化组件

用户:“扁平化此代码库中的组件层次结构”

技能将:
1. 识别有层次结构问题的组件
2. 分析孤儿类
3. 建议合并或拆分策略
4. 创建重构计划
5. 估算工作量

示例3:组件结构分析

用户:“分析组件结构以查找层次结构问题”

技能将:
1. 映射组件命名空间结构
2. 识别有代码的根命名空间
3. 查找基于组件构建的组件
4. 标记层次结构违规
5. 提供建议

逐步过程

  1. 扫描结构:映射组件命名空间层次结构
  2. 识别问题:查找孤儿类和组件嵌套
  3. 分析选项:确定扁平化策略(合并 vs 拆分)
  4. 创建计划:生成步骤化的重构计划
  5. 执行:重构组件以移除层次结构

使用时机

应用此技能当:

  • 在收集通用领域组件后(模式2)
  • 在确定组件依赖之前(模式4)
  • 当组件有嵌套结构时
  • 查找根命名空间中的孤儿类时
  • 准备领域分组时
  • 清理组件结构时
  • 确保组件仅作为叶子节点时

核心概念

组件定义

组件由目录/命名空间结构中的叶子节点识别:

  • 叶子节点:包含源文件的最深层目录
  • 组件:叶子节点命名空间中的源代码文件
  • 子域:已被扩展的父命名空间

关键规则:组件仅作为叶子节点存在。如果一个命名空间被扩展,父节点成为子域,而不是组件。

根命名空间

根命名空间是一个已被扩展的命名空间节点:

  • 扩展:另一个命名空间节点添加在其下方
  • 示例ss.survey 扩展为 ss.survey.templates
  • 结果ss.survey 成为根命名空间(子域)

孤儿类

孤儿类是根命名空间中的源文件:

  • 位置:根命名空间(非叶子节点)
  • 问题:没有可定义的组件与之关联
  • 解决方案:移动到叶子节点命名空间(组件)

示例

ss.survey/              ← 根命名空间(被.templates扩展)
├── Survey.js           ← 孤儿类(在根命名空间中)
└── templates/          ← 组件(叶子节点)
    └── Template.js

扁平化策略

策略1:向下合并

  • 将代码从叶子节点移动到根命名空间
  • 使根命名空间成为组件
  • 示例:移动 ss.survey.templatesss.survey

策略2:向上拆分

  • 将代码从根命名空间移动到新的叶子节点
  • 从根命名空间创建新组件
  • 示例:拆分 ss.surveyss.survey.create + ss.survey.process

策略3:移动共享代码

  • 将共享代码移动到专用组件
  • 创建 .shared 组件
  • 示例:ss.survey 共享代码 → ss.survey.shared

分析过程

阶段1:映射组件结构

扫描目录/命名空间结构以识别层次结构:

  1. 映射命名空间树

    • 构建所有命名空间的树
    • 识别父子关系
    • 标记叶子节点(组件)
  2. 识别根命名空间

    • 查找已被扩展的命名空间
    • 标记为根命名空间(子域)
    • 注意哪些命名空间扩展了它们
  3. 定位源文件

    • 查找每个命名空间中的所有源文件
    • 映射文件到其命名空间位置
    • 识别根命名空间中的文件

示例结构映射

## 组件结构映射

ss.survey/ ← 根命名空间(已扩展)
├── Survey.js ← 孤儿类
├── SurveyProcessor.js ← 孤儿类
└── templates/ ← 组件(叶子节点)
    ├── EmailTemplate.js
    └── SMSTemplate.js

ss.ticket/ ← 根命名空间(已扩展)
├── Ticket.js ← 孤儿类
├── assign/ ← 组件(叶子节点)
│   └── TicketAssign.js
└── route/ ← 组件(叶子节点)
    └── TicketRoute.js

阶段2:识别孤儿类

查找根命名空间中的源文件:

  1. 扫描根命名空间

    • 检查每个根命名空间是否有源文件
    • 识别孤儿文件
    • 统计每个根命名空间的孤儿文件数
  2. 分类孤儿类

    • 共享代码:常见工具、接口、抽象类
    • 领域代码:应位于组件中的业务逻辑
    • 混合:共享和领域代码的组合
  3. 评估影响

    • 有多少文件是孤儿的?
    • 它们包含什么功能?
    • 哪些组件依赖它们?

示例孤儿类检测

## 发现的孤儿类

### 根命名空间:ss.survey

**孤儿文件**(5个文件):

- Survey.js(领域代码 - 调查创建)
- SurveyProcessor.js(领域代码 - 调查处理)
- SurveyValidator.js(共享代码 - 验证)
- SurveyFormatter.js(共享代码 - 格式化)
- SurveyConstants.js(共享代码 - 常量)

**分类**:

- 领域代码:2个文件(应位于组件中)
- 共享代码:3个文件(应位于.shared组件中)

**依赖**:被ss.survey.templates组件使用

阶段3:分析扁平化选项

为每个根命名空间确定最佳扁平化策略:

  1. 选项1:向下合并

    • 将叶子节点代码移动到根命名空间
    • 使根命名空间成为组件
    • 使用当:叶子节点小、功能相关时
  2. 选项2:向上拆分

    • 将根命名空间代码移动到新的叶子节点
    • 从根创建多个组件
    • 使用当:根命名空间有不同功能区域时
  3. 选项3:移动共享代码

    • 提取共享代码到.shared组件
    • 保留领域代码在根或拆分
    • 使用当:根命名空间有共享工具时

示例扁平化分析

## 扁平化选项分析

### 根命名空间:ss.survey

**当前状态**:

- 根命名空间:5个孤儿文件
- 叶子组件:ss.survey.templates(7个文件)

**选项1:向下合并** ✅ 推荐

- 将模板代码移动到ss.survey
- 结果:单一组件ss.survey
- 工作量:低(移动7个文件)
- 理由:模板小,与调查功能相关

**选项2:向上拆分**

- 创建ss.survey.create(2个文件)
- 创建ss.survey.process(1个文件)
- 创建ss.survey.shared(3个文件)
- 保留ss.survey.templates(7个文件)
- 工作量:高(创建多个组件)
- 理由:更细粒度,但可能过度工程

**选项3:移动共享代码**

- 创建ss.survey.shared(3个共享文件)
- 保留领域代码在根(2个文件)
- 保留ss.survey.templates(7个文件)
- 工作量:中等
- 理由:分离共享和领域,但仍存在层次结构

阶段4:创建扁平化计划

为每个根命名空间生成重构计划:

  1. 选择策略

    • 选择最佳扁平化选项
    • 考虑工作量、复杂性、可维护性
  2. 规划重构步骤

    • 列出要移动的文件
    • 识别目标命名空间
    • 注意要更新的依赖
  3. 估算工作量

    • 重构时间
    • 风险评估
    • 测试要求

示例扁平化计划

## 扁平化计划

### 优先级:高

**根命名空间:ss.survey**

**策略**:向下合并

**步骤**:

1. 将文件从ss.survey.templates/移动到ss.survey/
   - EmailTemplate.js
   - SMSTemplate.js
   - [5个其他文件]

2. 更新依赖组件的导入
   - 更新引用从ss.survey.templates._到ss.survey._

3. 移除ss.survey.templates/目录

4. 更新命名空间声明
   - 将命名空间从ss.survey.templates更改为ss.survey

5. 运行测试以验证更改

**工作量**:2-3天
**风险**:低(模板是自包含的)
**依赖**:无

阶段5:执行扁平化

执行重构:

  1. 移动文件

    • 移动源文件到目标命名空间
    • 更新文件路径和导入
  2. 更新引用

    • 更新依赖组件的导入
    • 更新命名空间声明
    • 更新目录结构
  3. 验证更改

    • 运行测试
    • 检查损坏的引用
    • 验证组件结构

输出格式

孤儿类报告

## 孤儿类分析

### 根命名空间:ss.survey

**状态**:⚠️ 有孤儿类

**孤儿文件**(5个文件):

- Survey.js(领域代码)
- SurveyProcessor.js(领域代码)
- SurveyValidator.js(共享代码)
- SurveyFormatter.js(共享代码)
- SurveyConstants.js(共享代码)

**叶子组件**:

- ss.survey.templates(7个文件)

**问题**:根命名空间包含代码但被叶子组件扩展

**建议**:将模板合并到根命名空间

组件层次结构问题

## 组件层次结构问题

| 根命名空间 | 孤儿文件 | 叶子组件                 | 问题                | 建议        |
| ---------- | -------- | ------------------------ | ------------------- | ----------- |
| ss.survey  | 5        | 1(templates)           | 有孤儿类           | 向下合并    |
| ss.ticket  | 45       | 2(assign, route)      | 孤儿代码多         | 向上拆分    |
| ss.reporting | 0      | 3(tickets, experts, financial) | 无问题 | ✅ OK |

扁平化计划

## 扁平化计划

### 优先级:高

**ss.survey** → 向下合并

- 移动7个文件从templates到根
- 工作量:2-3天
- 风险:低

### 优先级:中等

**ss.ticket** → 向上拆分

- 创建ss.ticket.maintenance(30个文件)
- 创建ss.ticket.completion(10个文件)
- 创建ss.ticket.shared(5个文件)
- 工作量:1周
- 风险:中等

分析清单

结构映射

  • [ ] 映射所有命名空间层次结构
  • [ ] 识别根命名空间
  • [ ] 定位所有源文件
  • [ ] 标记叶子节点(组件)

孤儿类检测

  • [ ] 扫描根命名空间以查找源文件
  • [ ] 识别孤儿类
  • [ ] 分类孤儿类(共享/领域/混合)
  • [ ] 评估影响和依赖

扁平化分析

  • [ ] 分析合并选项
  • [ ] 分析拆分选项
  • [ ] 分析共享代码提取选项
  • [ ] 为每个根命名空间选择最佳策略

计划创建

  • [ ] 选择扁平化策略
  • [ ] 创建重构步骤
  • [ ] 估算工作量和风险
  • [ ] 优先级排序工作

执行

  • [ ] 移动文件到目标命名空间
  • [ ] 更新导入和引用
  • [ ] 更新命名空间声明
  • [ ] 通过测试验证更改

实现说明

对于Node.js/Express应用

组件通常在services/目录中:

services/
├── survey/              ← 根命名空间(已扩展)
│   ├── Survey.js       ← 孤儿类
│   └── templates/      ← 组件(叶子节点)
│       └── Template.js

扁平化

  • 合并:移动templates/文件到survey/
  • 拆分:创建survey/create/survey/process/
  • 共享:创建survey/shared/用于工具

对于Java应用

组件通过包结构识别:

com.company.survey       ← 根包(已扩展)
├── Survey.java         ← 孤儿类
└── templates/          ← 组件(叶子包)
    └── Template.java

扁平化

  • 合并:移动templates类到survey
  • 拆分:创建survey.createsurvey.process
  • 共享:创建survey.shared

检测策略

查找有代码的根命名空间

// 查找包含源文件的根命名空间
function findRootNamespacesWithCode(namespaces, sourceFiles) {
  const rootNamespaces = namespaces.filter((ns) => {
    // 检查命名空间是否被扩展
    const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))

    // 检查命名空间是否包含源文件
    const hasFiles = sourceFiles.some((f) => f.namespace === ns)

    return hasChildren && hasFiles
  })

  return rootNamespaces
}

查找孤儿类

// 查找根命名空间中的孤儿类
function findOrphanedClasses(rootNamespaces, sourceFiles) {
  const orphaned = []

  rootNamespaces.forEach((rootNs) => {
    const files = sourceFiles.filter((f) => f.namespace === rootNs)
    orphaned.push({
      rootNamespace: rootNs,
      files: files,
      count: files.length,
    })
  })

  return orphaned
}

适应性函数

扁平化组件后,创建自动化检查:

根命名空间中无源代码

// 如果根命名空间中存在源代码,则发出警报
function checkRootNamespaceCode(namespaces, sourceFiles) {
  const violations = []

  namespaces.forEach((ns) => {
    // 检查命名空间是否被扩展
    const hasChildren = namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))

    if (hasChildren) {
      // 检查命名空间是否包含源文件
      const files = sourceFiles.filter((f) => f.namespace === ns)

      if (files.length > 0) {
        violations.push({
          namespace: ns,
          files: files.map((f) => f.name),
          issue: '根命名空间包含源文件(孤儿类)',
        })
      }
    }
  })

  return violations
}

组件仅作为叶子节点

// 确保组件仅作为叶子节点存在
function validateComponentStructure(namespaces, sourceFiles) {
  const violations = []

  // 查找所有叶子节点(组件)
  const leafNodes = namespaces.filter((ns) => {
    return !namespaces.some((n) => n.startsWith(ns + '.') || n.startsWith(ns + '/'))
  })

  // 检查所有源文件是否在叶子节点中
  sourceFiles.forEach((file) => {
    if (!leafNodes.includes(file.namespace)) {
      violations.push({
        file: file.name,
        namespace: file.namespace,
        issue: '源文件不在叶子节点(组件)中',
      })
    }
  })

  return violations
}

最佳实践

应做 ✅

  • 确保组件仅作为叶子节点存在
  • 移除根命名空间中的孤儿类
  • 基于功能选择扁平化策略
  • 功能相关时合并
  • 功能不同时拆分
  • 提取共享代码到.shared组件
  • 扁平化后更新所有引用
  • 通过测试验证更改

不应做 ❌

  • 不要在根命名空间中留下孤儿类
  • 不要在其他组件之上创建组件
  • 不要跳过移动文件后更新导入
  • 不要在不分析影响的情况下扁平化
  • 不要不一致地混合扁平化策略
  • 不要扁平化时忽略共享代码
  • 不要跳过重构后测试

常见模式

模式1:简单合并

之前

ss.survey/
├── Survey.js           ← 孤儿
└── templates/          ← 组件
    └── Template.js

之后

ss.survey/              ← 组件(叶子节点)
├── Survey.js
└── Template.js

模式2:功能拆分

之前

ss.ticket/              ← 根命名空间
├── Ticket.js           ← 孤儿(45个文件)
├── assign/             ← 组件
└── route/              ← 组件

之后

ss.ticket/              ← 子域
├── maintenance/        ← 组件
│   └── Ticket.js
├── completion/        ← 组件
│   └── TicketCompletion.js
├── assign/             ← 组件
└── route/              ← 组件

模式3:共享代码提取

之前

ss.survey/              ← 根命名空间
├── Survey.js           ← 领域代码
├── SurveyValidator.js  ← 共享代码
└── templates/          ← 组件

之后

ss.survey/              ← 组件
├── Survey.js
└── shared/             ← 组件
    └── SurveyValidator.js

后续步骤

扁平化组件后:

  1. 应用确定组件依赖模式 - 分析耦合
  2. 创建组件域 - 将组件分组到域中
  3. 创建域服务 - 提取域到服务

注意

  • 组件必须仅作为叶子节点存在
  • 有代码的根命名空间是问题所在
  • 扁平化提高组件清晰度
  • 基于功能选择扁平化策略
  • 共享代码应位于专用组件中
  • 移动文件后始终更新引用
  • 扁平化后彻底测试