You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

6.0 KiB

作为 Java 架构审计师,基于您提供的代码库(包含核心任务及选做任务的实现),以下是针对 策略模式解耦Repository 封装工厂性能 的深度审计报告。


📋 架构审计报告

1. 策略模式解耦性审计 (Strategy Pattern Decoupling)

审计结论:基本正确,符合开闭原则。

  • 现状分析
    • CrawlCommandAnalyzeCommand 均通过 StrategyFactory 获取策略,并未在命令内部硬编码 if (url.contains("hnu")) 等具体网站逻辑。
    • 解析逻辑完全下沉到 HnuNewsStrategy 等具体策略类中。
    • AnalyzeCommand 复用了 CrawlStrategyparse 方法,实现了“一次实现,多处复用”的目标。
  • 潜在风险
    • 如果 supports() 方法内部包含复杂的 URL 解析逻辑,可能会污染策略接口。
    • AnalyzeCommand 目前虽然不存数据,但如果未来需要“分析后自动保存”,它可能会直接调用 repository,导致职责不清。
  • 改进建议
    1. 保持现状:目前的解耦设计是合理的,无需大改。
    2. 接口纯净化:确保 CrawlStrategy 接口中不包含任何与“存储”相关的逻辑,只关注“解析”。
    3. 异常隔离:在 CrawlCommand 中捕获 Jsoup 异常时,建议区分网络异常和解析异常,以便策略层能针对性处理(例如重试或跳过)。

2. Repository 数据访问封装审计 (Repository Encapsulation)

⚠️ 审计结论:封装性良好,但存在数据模型可变性风险。

  • 现状分析
    • ArticleRepository 内部持有 List<Article>,外部无法直接获取引用(getAll() 返回 Collections.unmodifiableList)。
    • addAll 方法增加了 null 检查,符合防御性编程。
    • 命令层(CrawlCommand)通过 repository.add() 操作数据,没有绕过 Repository 直接操作 List。
  • 潜在风险
    1. 模型可变性Article 类提供了 setTitle, setContent 等 Setter 方法。这意味着外部获取到 Article 对象后,可以修改其状态,破坏了 Repository 的数据一致性封装。
    2. 线程安全ArticleRepository 内部使用 ArrayList,在多线程环境下(如未来扩展并发爬虫)存在 ConcurrentModificationException 风险。
    3. 资源泄露ConsoleView 中的 Scanner 未关闭,虽然程序退出时 OS 会回收,但规范上应实现 AutoCloseable
  • 改进建议
    1. 不可变模型:将 Article 类改为 不可变类 (Immutable)。移除所有 Setter 方法,构造函数中初始化所有字段。
    2. 线程安全:将 ArticleRepository 内部 List 替换为 CopyOnWriteArrayListCollections.synchronizedList,或者在 Repository 层面加锁。
    3. 资源管理ConsoleView 实现 AutoCloseable 接口,在 Main 中通过 try-with-resources 关闭 Scanner。

3. 策略工厂匹配逻辑性能审计 (Factory Performance)

审计结论:存在显著性能隐患,不适合大规模扩展。

  • 现状分析
    • StrategyFactory.getStrategy() 中,使用了 strategies.stream().sorted(...).filter(...)
    • 性能隐患:每次调用 getStrategy(即每次爬虫请求)都会执行一次 排序操作 (O(N log N))。如果网站数量增加到 100 个,且用户频繁调用 crawl 命令,这会带来不必要的 CPU 开销。
    • 匹配逻辑:目前依赖 supports() 的线性遍历。如果 URL 规则复杂,正则匹配本身也有开销。
  • 改进建议
    1. 预排序 (Pre-sorting)
      • 方案:在 StrategyFactory构造函数 中完成排序,而不是在 getStrategy 方法中。
      • 代码
      public StrategyFactory() {
          strategies.add(new HnuNewsStrategy());
          // ...
          Collections.sort(strategies, (s1, s2) -> Integer.compare(s2.getPriority(), s1.getPriority()));
      }
      
    2. 路由优化 (Routing Optimization)
      • 如果网站数量超过 50 个,线性遍历 (O(N)) 效率会下降。
      • 方案:使用 Map<String, CrawlStrategy> 进行前缀匹配,或使用 Trie 树 (字典树) 存储 URL 域名前缀。
      • 示例:将 blog.example.comnews.hnu.edu.cn 作为 Key 存入 Map,匹配时直接 map.get(url),将复杂度降为 O(1)
    3. 正则缓存:确保 Pattern 对象是 static final 的(当前代码已做到),避免重复编译正则表达式。

🚀 综合改进建议清单 (Action Items)

优先级 模块 问题描述 改进方案
P0 StrategyFactory getStrategy 中每次调用都排序 移至构造函数排序,消除 O(N log N) 重复计算。
P0 Article 存在 Setter 方法,数据可被篡改 移除 Setter,改为全参构造函数,实现不可变对象。
P1 ArticleRepository ArrayList 非线程安全 若需并发,改为 CopyOnWriteArrayList 或加锁。
P1 ConsoleView Scanner 未关闭 实现 AutoCloseable 并在 Main 中关闭。
P2 StrategyFactory 100+ 网站时线性匹配慢 引入 URL 前缀映射表Trie 树 优化匹配。
P3 CrawlCommand 异常捕获过宽 区分 IOException (网络) 和 ParserException (解析)。

📝 审计总结

当前架构在 设计模式分层解耦 上做得非常出色,特别是策略模式与命令模式的结合,使得系统具备极强的扩展性。

最大的瓶颈在于 StrategyFactory 的运行时性能(每次调用都排序)和 数据模型的封装性Article 可变)。建议优先修复这两个问题,即可支撑从“教学 Demo"到“生产级爬虫系统”的跨越。