{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f5d8e56d",
   "metadata": {},
   "source": [
    "# 降低认知负荷"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9a9a366-7fd3-422b-b3bc-b0bc00374da6",
   "metadata": {},
   "source": [
    "## 目标\n",
    "- 理解封装方法（函数、类、模块）在代码组织中的作用。\n",
    "\n",
    "封装方法：\n",
    "- 函数封装：将重复逻辑封装为函数，降低耦合，提高复用性。\n",
    "- 类封装：将数据和方法绑定，增强代码组织性和扩展性。\n",
    "- 文件封装：通过文件模块化，符合工程化开发规范。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5881283-c295-4433-8edd-f915201a5f43",
   "metadata": {},
   "source": [
    "## A ：函数封装\n",
    "\n",
    "提炼出若干函数，减少代码的复杂性，提高可读性和可维护性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7beadc81-f939-4ac5-b885-407c6810b7de",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "def read_file(file_path):\n",
    "    \"\"\"读取单个文件内容\"\"\"\n",
    "    try:\n",
    "        with open(file_path, 'r', encoding='utf-8') as f:\n",
    "            return f.read()\n",
    "    except Exception as e:\n",
    "        print(f\"Error reading {file_path}: {e}\")\n",
    "        return \"\"\n",
    "\n",
    "def get_words(text):\n",
    "    \"\"\"简单分词（按空格）\"\"\"\n",
    "    return text.split()\n",
    "\n",
    "def count_words(words):\n",
    "    \"\"\"统计词频\"\"\"\n",
    "    word_count = {}\n",
    "    for word in words:\n",
    "        word_count[word] = word_count.get(word, 0) + 1\n",
    "    return word_count\n",
    "\n",
    "def get_top_n(word_count, n=10):\n",
    "    \"\"\"获取前 N 高频词\"\"\"\n",
    "    return sorted(word_count.items(), key=lambda x: x[1], reverse=True)[:n]\n",
    "\n",
    "def main():\n",
    "    \"\"\"主函数，控制流程\"\"\"\n",
    "    word_count = {}\n",
    "    data_dir = 'data'\n",
    "    \n",
    "    # 顺序结构：按步骤读取文件、处理文本\n",
    "    for file in os.listdir(data_dir):\n",
    "        file_path = os.path.join(data_dir, file)\n",
    "        # 选择结构：检查文件是否为 txt\n",
    "        if file_path.endswith('.txt'):\n",
    "            text = read_file(file_path)\n",
    "            # 循环结构：处理每个文件的词\n",
    "            words = get_words(text)\n",
    "            file_word_count = count_words(words)\n",
    "            # 合并词频\n",
    "            for word, count in file_word_count.items():\n",
    "                word_count[word] = word_count.get(word, 0) + count\n",
    "    \n",
    "    # 输出结果\n",
    "    top_words = get_top_n(word_count)\n",
    "    for word, count in top_words:\n",
    "        print(f\"{word}: {count}\")\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f7218a3-43d2-4159-9854-9880020c42fc",
   "metadata": {},
   "source": [
    "### 改进分析\n",
    " - 逻辑分层：main() 函数清晰定义了程序执行步骤（读取文件 -> 分词 -> 统计 -> 输出）。\n",
    " - 模块化：将功能拆分为函数（read_file、get_words、count_words、get_top_n），提高代码复用性和可读性。\n",
    " - 错误处理：增加 try-except 处理文件读取异常。提高程序健壮性\n",
    " - 工程质量提升：\n",
    "    - 可读性：函数命名本身就帮助理解代码，逻辑分块。\n",
    "    - 可维护性：修改某部分功能（如分词逻辑）只需改对应函数。\n",
    "    - 复用性：函数可复用在其他类似任务中。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50737966-57c9-4daf-ac3b-6a1c73b18136",
   "metadata": {},
   "source": [
    "## B：类封装\n",
    "\n",
    "通过类封装功能，进一步提高代码的模块化、可扩展性和复用性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "81aa7f9c-de28-4a7a-8ba1-130c3e5e4f7f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import jieba\n",
    "from collections import Counter\n",
    "\n",
    "class TextAnalyzer:\n",
    "    \"\"\"文本分析类，封装词频统计功能\"\"\"\n",
    "    def __init__(self, data_dir='data', top_n=10):\n",
    "        self.data_dir = data_dir\n",
    "        self.top_n = top_n\n",
    "        self.word_count = Counter()\n",
    "\n",
    "    def read_file(self, file_path):\n",
    "        \"\"\"读取文件内容\"\"\"\n",
    "        try:\n",
    "            with open(file_path, 'r', encoding='utf-8') as f:\n",
    "                return f.read()\n",
    "        except Exception as e:\n",
    "            print(f\"Error reading {file_path}: {e}\")\n",
    "            return \"\"\n",
    "\n",
    "    def tokenize(self, text):\n",
    "        \"\"\"使用 jieba 进行中文分词\"\"\"\n",
    "        return jieba.lcut(text)\n",
    "\n",
    "    def process_file(self, file_path):\n",
    "        \"\"\"处理单个文件\"\"\"\n",
    "        if file_path.endswith('.txt'):\n",
    "            text = self.read_file(file_path)\n",
    "            words = self.tokenize(text)\n",
    "            self.word_count.update(words)\n",
    "\n",
    "    def process_directory(self):\n",
    "        \"\"\"处理目录下所有文件\"\"\"\n",
    "        for file in os.listdir(self.data_dir):\n",
    "            file_path = os.path.join(self.data_dir, file)\n",
    "            self.process_file(file_path)\n",
    "\n",
    "    def get_top_words(self):\n",
    "        \"\"\"获取前 N 高频词\"\"\"\n",
    "        return self.word_count.most_common(self.top_n)\n",
    "\n",
    "    def run(self):\n",
    "        \"\"\"执行词频统计\"\"\"\n",
    "        self.process_directory()\n",
    "        top_words = self.get_top_words()\n",
    "        for word, count in top_words:\n",
    "            print(f\"{word}: {count}\")\n",
    "\n",
    "def main():\n",
    "    analyzer = TextAnalyzer(data_dir='data', top_n=10)\n",
    "    analyzer.run()\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62e780d4-94de-4830-89c2-ab2c96500fc5",
   "metadata": {},
   "source": [
    "### 改进分析\n",
    "- 面向对象封装：\n",
    "  - 使用 TextAnalyzer 类将所有功能封装为一个对象，数据（如 word_count）和方法（如 tokenize）绑定在一起。\n",
    "  - 通过 __init__ 提供配置（如 data_dir 和 top_n），提高灵活性。\n",
    "\n",
    "  \n",
    "- 模块化：\n",
    "    - 类方法分工明确（如 read_file、tokenize、process_file），便于扩展。\n",
    " \n",
    "    \n",
    "- 工程质量提升：\n",
    "    - 可扩展性：可通过继承 TextAnalyzer 添加新功能（如支持其他分词器或文件格式）。\n",
    "    - 复用性：类可实例化多次，用于不同目录或参数。\n",
    "    - 可维护性：逻辑集中在类中，修改相对安全。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b4e17c4-f47e-4245-b3d9-e40fde0a2e04",
   "metadata": {},
   "source": [
    "# C：引入文件模块封装\n",
    "将代码进一步模块化到不同文件，引入配置文件和停用词过滤。"
   ]
  },
  {
   "cell_type": "raw",
   "id": "aadb5aea-8cc5-4a0f-9f5b-7eab28e90f1a",
   "metadata": {},
   "source": [
    "目录结构\n",
    "\n",
    "project/\n",
    "├── data/                    # 小说文本目录\n",
    "├── config.yaml              # 配置文件\n",
    "├── stop_words.txt           # 停用词文件\n",
    "├── text_analyzer.py         # 分析模块\n",
    "├── main.py                  # 主程序"
   ]
  },
  {
   "cell_type": "raw",
   "id": "2de4767b-8928-4f3f-8c8b-3c3cba2bc98a",
   "metadata": {},
   "source": [
    "# config.yaml\n",
    "\n",
    "data_dir: data\n",
    "top_n: 10\n",
    "stop_words_file: stop_words.txt\n",
    "output_file: output.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9b442d61-c937-4757-b7b4-b6fc047c3529",
   "metadata": {},
   "outputs": [],
   "source": [
    "# text_analyzer.py\n",
    "\n",
    "import os\n",
    "import jieba\n",
    "from collections import Counter\n",
    "import yaml\n",
    "\n",
    "class TextAnalyzer:\n",
    "    def __init__(self, config_path='config.yaml'):\n",
    "        with open(config_path, 'r', encoding='utf-8') as f:\n",
    "            config = yaml.safe_load(f)\n",
    "        self.data_dir = config['data_dir']\n",
    "        self.top_n = config['top_n']\n",
    "        self.stop_words_file = config['stop_words_file']\n",
    "        self.output_file = config['output_file']\n",
    "        self.word_count = Counter()\n",
    "        self.stop_words = self.load_stop_words()\n",
    "\n",
    "    def load_stop_words(self):\n",
    "        \"\"\"加载停用词\"\"\"\n",
    "        try:\n",
    "            with open(self.stop_words_file, 'r', encoding='utf-8') as f:\n",
    "                return set(line.strip() for line in f if line.strip())\n",
    "        except Exception as e:\n",
    "            print(f\"Error loading stop words: {e}\")\n",
    "            return set()\n",
    "\n",
    "    def read_file(self, file_path):\n",
    "        \"\"\"读取文件内容\"\"\"\n",
    "        try:\n",
    "            with open(file_path, 'r', encoding='utf-8') as f:\n",
    "                return f.read()\n",
    "        except Exception as e:\n",
    "            print(f\"Error reading {file_path}: {e}\")\n",
    "            return \"\"\n",
    "\n",
    "    def tokenize(self, text):\n",
    "        \"\"\"中文分词并过滤停用词\"\"\"\n",
    "        words = jieba.lcut(text)\n",
    "        return [word for word in words if word not in self.stop_words]\n",
    "\n",
    "    def process_file(self, file_path):\n",
    "        \"\"\"处理单个文件\"\"\"\n",
    "        if file_path.endswith('.txt'):\n",
    "            text = self.read_file(file_path)\n",
    "            words = self.tokenize(text)\n",
    "            self.word_count.update(words)\n",
    "\n",
    "    def process_directory(self):\n",
    "        \"\"\"处理目录下所有文件\"\"\"\n",
    "        for file in os.listdir(self.data_dir):\n",
    "            file_path = os.path.join(self.data_dir, file)\n",
    "            self.process_file(file_path)\n",
    "\n",
    "    def get_top_words(self):\n",
    "        \"\"\"获取前 N 高频词\"\"\"\n",
    "        return self.word_count.most_common(self.top_n)\n",
    "\n",
    "    def save_results(self, top_words):\n",
    "        \"\"\"保存结果到文件\"\"\"\n",
    "        with open(self.output_file, 'w', encoding='utf-8') as f:\n",
    "            for word, count in top_words:\n",
    "                f.write(f\"{word}: {count}\\n\")\n",
    "\n",
    "    def run(self):\n",
    "        \"\"\"执行词频统计并保存结果\"\"\"\n",
    "        self.process_directory()\n",
    "        top_words = self.get_top_words()\n",
    "        self.save_results(top_words)\n",
    "        for word, count in top_words:\n",
    "            print(f\"{word}: {count}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22f58992-0108-4c90-894d-e756e7301a5a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# main.py\n",
    "\n",
    "from text_analyzer import TextAnalyzer\n",
    "\n",
    "def main():\n",
    "    analyzer = TextAnalyzer()\n",
    "    analyzer.run()\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18d27410-8923-4662-a6b7-8e027609506e",
   "metadata": {},
   "source": [
    "## 改进分析\n",
    "\n",
    "- 模块化：将分析逻辑放入 text_analyzer.py，主程序 main.py 仅负责调用，符合工程化项目结构。\n",
    "- 配置文件：通过 config.yaml 配置参数，增强灵活性，无需修改代码即可更改目录、输出文件等。\n",
    "- 输出到文件：增加 save_results 方法，支持结果持久化。\n",
    "- 工程质量提升：\n",
    "    - 可维护性：配置文件和模块化分离了配置与逻辑，修改配置无需动代码。    \n",
    "    - 复用性：模块可导入到其他项目。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10876929-69f9-43bf-ba2d-a5d7bb11f22b",
   "metadata": {},
   "source": [
    "### 工程质量总结\n",
    "- 分离配置与逻辑，降低维护成本。\n",
    "- 模块化和面向对象设计支持功能扩展。\n",
    "- 错误处理提高程序鲁棒性。"
   ]
  },
  {
   "cell_type": "raw",
   "id": "60ba30d8-d8c2-4183-996e-376ff71716bf",
   "metadata": {},
   "source": [
    "## 另外一种文件模块化设计（分层架构）示例\n",
    "\n",
    "将代码拆分为独立模块，每个模块仅负责单一职责：\n",
    "    - 数据读取层：遍历目录、读取文件内容\n",
    "    - 数据处理层：文本清洗、分词、统计词频\n",
    "    - 结果输出层：排序并输出前10高频词\n",
    "\n",
    "目录结构：\n",
    "project/\n",
    "├── data_loader.py    # 数据读取模块\n",
    "├── text_processor.py # 数据处理模块\n",
    "├── output_handler.py # 结果输出模块\n",
    "└── main.py           # 主程序入口"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "517759ac-c4cf-402e-86f1-a9fae0d88bbb",
   "metadata": {},
   "source": [
    "# 运行说明\n",
    "\n",
    "环境准备：\n",
    "- 安装 Python 3.8+。\n",
    "- 安装依赖：pip install jieba pyyaml。\n",
    "- 准备 data 目录，放入 100 个 txt 文件。\n",
    "- 创建 stop_words.txt 和 config.yaml。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
