# DISK 项目：最小知识原则（迪米特法则）违反情况分析报告

本文档基于对 `DISK` 项目核心模块（`disk.py`, `extractor/`, `merger/`, `manager/`, `models/`）的代码审计，指出其中违反**最小知识原则（Least Knowledge Principle / Law of Demeter）**的设计缺陷，并提出改进建议。

---

## 核心原则定义
**最小知识原则（迪米特法则）**：一个软件实体应当尽可能少地与其他实体发生相互作用。即：只与你的直接朋友交谈，不跟“陌生人的朋友”说话。

---

## 1. 穿透访问内部属性（火车残骸现象）

### 表现地点：`extractor/extractor.py`
**代码示例：**
```python
# Extractor 类中直接访问了 Parser 内部的 embeddings 对象
self.parser.embeddings.embed_query(entity["name"])
```
*   **分析：** `Extractor` 实例持有 `Parser`，而 `Parser` 持有 `embeddings`。`Extractor` 越过 `Parser` 直接操作其内部构件。
*   **违反原因：** `Extractor` 知道了它不该知道的秘密——`Parser` 是如何实现向量化的。
*   **后果：** 如果 `Parser` 未来更换了向量化方式（例如改为调用 REST API 而不再持有 `embeddings` 对象），`Extractor` 必须跟着修改代码。

### 表现地点：`disk.py`
**代码示例：**
```python
# DISK 类通过 manager 访问 kg 实例，再访问其内部的列表
all_entities = self.kg_manager.kg.entities
```
*   **分析：** 典型的“火车残骸”式调用：`A -> B -> C -> D`。
*   **改进建议：** `KGManager` 应提供 `get_all_entities()` 方法，隐藏 `KnowledgeGraph` 的内部结构。

---

## 2. 外部直接干预对象状态

### 表现地点：`disk.py`
**代码示例：**
```python
# DISK 主类直接修改了抽取器的内部属性
self.entities_extractor.prompts = prompts
self.relations_extractor.prompts = prompts
self.extractor.prompts = prompts
```
*   **分析：** `DISK` 类在检测到语言后，直接覆盖了 `Extractor` 实例的成员变量。
*   **违反原因：** 它假设了 `Extractor` 内部一定有一个名为 `prompts` 的属性，这破坏了封装性。
*   **改进建议：** 应该在 `Extractor` 中定义 `update_language_config(prompts)` 方法。

---

## 3. 逻辑职责分配不当（上帝类倾向）

### 表现地点：`merger/merger.py`
**代码示例：**
```python
# Merger 手动拼凑新的 Entity 对象，深入了解其所有字段
merged_entity = Entity(
    name=e1.name,
    label=e1.label,
    embedding=emb1[idx1].tolist(),
    description=e1.description if hasattr(e1, 'description') else "",
)
```
*   **分析：** `Merger` 类作为一个工具类，却对 `Entity` 的构造函数、属性名（`description`）、甚至向量的转换细节（`tolist()`）了如指掌。
*   **违反原因：** `Merger` 知道得太多了。它不仅知道如何合并，还知道如何“制造”实体。
*   **改进建议：** 应该在 `Entity` 类中实现 `merge_with(other)` 方法。

---

## 4. 领域模型与持久化层的深度耦合

### 表现地点：`models/neo4j_connector.py`
**代码示例：**
```python
# 连接器深入读取实体的每一个字段来构建 Cypher 查询
parameters = {
    "name": entity.name, 
    "embedding": entity.embedding, 
    "description": entity.description if hasattr(entity, 'description') else ""
}
```
*   **分析：** 数据库连接器应该只负责执行查询。目前它必须了解 `Entity` 所有的属性名称。
*   **后果：** 只要 `Entity` 增加或修改一个字段（例如把 `name` 改为 `display_name`），连接器就会崩溃。
*   **改进建议：** `Entity` 应该提供一个 `to_dict()` 方法，连接器只负责消费这个字典。

---

## 总结与改进方案

项目目前的实现风格偏向于**过程式拼装**，类更像是带方法的“数据结构”。

### 改进路线图：
1.  **封装委派**：在 `Parser` 中提供 `embed(text)` 接口，禁止外部直接访问 `self.embeddings`。
2.  **隐藏内部结构**：`KGManager` 应该作为 `KnowledgeGraph` 的唯一出口，禁止外部通过 `.kg` 属性进行链式访问。
3.  **行为下移**：将属性合并、对象克隆、序列化等逻辑从 `Merger` 和 `Connector` 中移回 `Entity` 和 `Relation` 类中。
4.  **接口契约**：使用方法调用代替直接属性赋值，确保对象内部状态的安全性。
