# W10 作业提交:设计模式实战 ## 目录结构 ``` w10/ └── src/ └── main/ └── java/ └── com/ └── example/ └── datacollect/ ├── Main.java ├── command/ │ ├── Command.java │ ├── CrawlCommand.java │ ├── AnalyzeCommand.java │ ├── ListCommand.java │ ├── HelpCommand.java │ ├── ExitCommand.java │ └── HistoryCommand.java ├── controller/ │ └── CrawlerController.java ├── model/ │ └── Article.java ├── repository/ │ └── ArticleRepository.java ├── strategy/ │ ├── CrawlStrategy.java │ ├── StrategyFactory.java │ ├── HnuNewsStrategy.java │ ├── BlogStrategy.java │ ├── NewsStrategy.java │ └── GenericNewsStrategy.java └── view/ └── ConsoleView.java ``` ## 必做任务完成情况 ### 1. ArticleRepository 完善 ✅ - `add()`: 拒绝 null,抛出 IllegalArgumentException - `addAll()`: 拒绝 null 列表和列表中的 null 元素 - `getAll()`: 返回 `Collections.unmodifiableList()` 不可变视图 - `size()`: 返回文章数量 - `clear()`: 清空所有文章 ### 2. AnalyzeCommand ✅ - 复用策略解析但**不存储**到 Repository - 输出统计信息:文章总数、含作者/日期/内容的数量、使用的策略名称 - 显示前 3 篇文章标题作为预览 ### 3. AI 架构审计 ✅ #### 类签名汇总 ```java // Command 层 interface Command { void execute(String[], ArticleRepository); } class CrawlCommand(ConsoleView, StrategyFactory) class AnalyzeCommand(ConsoleView, StrategyFactory) class ListCommand(ConsoleView) class HelpCommand(ConsoleView) class ExitCommand(ConsoleView) class HistoryCommand(ConsoleView, List) // Controller 层 class CrawlerController(ConsoleView, ArticleRepository, StrategyFactory) // Repository 层 class ArticleRepository { add(), addAll(), getAll(), size(), clear() } // Strategy 层 interface CrawlStrategy { parse(), supports(), getPriority(), getPattern() } class StrategyFactory { getStrategy(url), register(), setDefaultStrategy() } class HnuNewsStrategy implements CrawlStrategy class BlogStrategy implements CrawlStrategy class NewsStrategy implements CrawlStrategy class GenericNewsStrategy implements CrawlStrategy (正则匹配) // Model 层 class Article { title, url, content, author, publishDate } // View 层 class ConsoleView ``` #### 架构审计结果 | 检查项 | 结果 | 说明 | |--------|------|------| | **策略解耦** | ✅ 优秀 | 策略接口与实现完全分离 | | **Repository 封装** | ✅ 优秀 | 使用不可变视图 + null 防御 | | **开闭原则** | ✅ 达标 | 新增网站只需加策略类 + 注册一行 | | **依赖倒置** | ✅ 良好 | Command/Strategy 依赖抽象接口 | | **单一职责** | ✅ 达标 | 每个类职责清晰 | | **循环依赖** | ✅ 无 | 依赖链单向 | ## 选做任务完成情况 ### 正则策略匹配 ✅ - `GenericNewsStrategy` 使用正则表达式 `.*\.(news|press|article)s?\..*` 匹配新闻类网站 ### 默认策略 ✅ - `StrategyFactory` 内置 `DefaultStrategy`,当没有匹配策略时返回空列表 ### 策略优先级 ✅ - `CrawlStrategy` 接口新增 `getPriority()` 默认方法 - `GenericNewsStrategy` 设置优先级为 5(高于默认优先级 1) - `StrategyFactory.getStrategy()` 遍历所有策略,选择优先级最高的匹配策略 ### 思考题答案 **Q: 两个策略都 supports 同一 URL 时怎么办?** **A:** 采用**优先级机制**解决: 1. 每个策略实现可以通过 `getPriority()` 返回优先级值 2. `StrategyFactory.getStrategy()` 遍历所有策略时,记录最高优先级 3. 如果多个策略都支持同一 URL,选择优先级最高的那个 4. 如果优先级相同,选择最先注册的策略(遍历顺序决定) 这种设计的优势: - 允许通用策略(如 `GenericNewsStrategy`)和专用策略(如 `HnuNewsStrategy`)共存 - 专用策略可设置更高优先级,确保精确匹配优先 - 通用策略作为兜底,提高系统兼容性 ## 命令功能对比 | 命令 | 功能 | 是否存储 | |------|------|----------| | `crawl ` | 爬取并存储文章 | ✅ 是 | | `analyze ` | 分析文章统计(不存储) | ❌ 否 | | `list` | 列出已存储文章 | - | | `history` | 显示命令历史 | - | | `help` | 显示帮助 | - | | `exit` | 退出程序 | - | ## 设计模式应用 1. **策略模式**:`CrawlStrategy` 接口定义标准,各策略独立实现 2. **工厂模式**:`StrategyFactory` 根据 URL 自动选择策略 3. **Repository 模式**:数据访问封装,防御式编程 4. **命令模式**:所有 Command 统一签名,易于扩展