diff --git a/W9/.gitignore b/W9/.gitignore new file mode 100644 index 0000000..0925d0a --- /dev/null +++ b/W9/.gitignore @@ -0,0 +1,4 @@ +*.jar +*.jar +*.class +*.log \ No newline at end of file diff --git a/W9/Command.java b/W9/Command.java new file mode 100644 index 0000000..f6e49b5 --- /dev/null +++ b/W9/Command.java @@ -0,0 +1,9 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import java.util.List; + +public interface Command { + String getName(); + void execute(String[] args, List
articles); +} diff --git a/W9/CrawlCommand.java b/W9/CrawlCommand.java new file mode 100644 index 0000000..cd0333e --- /dev/null +++ b/W9/CrawlCommand.java @@ -0,0 +1,49 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import com.example.datacollect.util.UrlValidator; +import com.example.datacollect.view.ConsoleView; +import java.util.List; + +/** + * 爬取命令(带 URL 验证) + */ +public class CrawlCommand implements Command { + private final ConsoleView view; + + public CrawlCommand(ConsoleView view) { + this.view = view; + } + + @Override + public String getName() { + return "crawl"; + } + + /** + * 获取命令别名 + */ + public String[] getAliases() { + return new String[]{"c"}; + } + + @Override + public void execute(String[] args, List
articles) { + if (args.length < 2) { + view.printError("Usage: crawl 或 c "); + return; + } + + String url = args[1]; + + // URL 格式验证 + if (!UrlValidator.isValid(url)) { + view.printError("URL 格式错误:" + UrlValidator.getValidationError(url)); + view.printInfo("示例:crawl https://www.example.com"); + return; + } + + view.printInfo("正在爬取:" + url); + // TODO: 实现实际爬取逻辑 + } +} diff --git a/W9/ExitCommand.java b/W9/ExitCommand.java new file mode 100644 index 0000000..e0eff23 --- /dev/null +++ b/W9/ExitCommand.java @@ -0,0 +1,24 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import com.example.datacollect.view.ConsoleView; +import java.util.List; + +public class ExitCommand implements Command { + private final ConsoleView view; + + public ExitCommand(ConsoleView view) { + this.view = view; + } + + @Override + public String getName() { + return "exit"; + } + + @Override + public void execute(String[] args, List
articles) { + view.printSuccess("Bye!"); + System.exit(0); + } +} diff --git a/W9/HelpCommand.java b/W9/HelpCommand.java new file mode 100644 index 0000000..f86cc06 --- /dev/null +++ b/W9/HelpCommand.java @@ -0,0 +1,23 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import com.example.datacollect.view.ConsoleView; +import java.util.List; + +public class HelpCommand implements Command { + private final ConsoleView view; + + public HelpCommand(ConsoleView view) { + this.view = view; + } + + @Override + public String getName() { + return "help"; + } + + @Override + public void execute(String[] args, List
articles) { + view.printInfo("Commands: crawl , list, help, exit"); + } +} diff --git a/W9/History.java b/W9/History.java new file mode 100644 index 0000000..3b5bb3a --- /dev/null +++ b/W9/History.java @@ -0,0 +1,27 @@ +package com.example.datacollect.command; + +import com.example.datacollect.model.Article; +import com.example.datacollect.view.ConsoleView; +import java.util.List; + +/** + * 查看历史命令 + */ +public class History implements Command { + private HistoryCommand historyCommand; + + public History(HistoryCommand historyCommand) { + this.historyCommand = historyCommand; + } + + @Override + public String getName() { + return "history"; + } + + @Override + public void execute(String[] args, List
articles) { + ConsoleView view = new ConsoleView(); + historyCommand.showHistory(view, articles); + } +} diff --git a/W9/List共享引用风险分析.md b/W9/List共享引用风险分析.md new file mode 100644 index 0000000..601edb3 --- /dev/null +++ b/W9/List共享引用风险分析.md @@ -0,0 +1,70 @@ +# List
共享引用的风险分析 + +## 问题描述 +在 Main.java 中,`List
articles` 被传递给多个对象(CrawlerController、Command 等),这存在共享引用风险。 + +## 主要风险 + +### 1. 数据不一致风险 +多个对象持有同一个 List 的引用,任何地方对 List 的修改都会影响其他地方。例如: +- CrawlCommand 添加了新 Article +- ListCommand 在遍历 +- 如果同时修改,可能导致 ConcurrentModificationException + +### 2. 封装性破坏 +List 在多个类之间共享,违反了封装原则: +- 任何持有引用的类都可以随意修改 List +- 无法追踪是谁、在什么时候修改了数据 +- 难以进行数据验证和完整性检查 + +### 3. 线程安全问题 +如果未来引入多线程: +- 多个线程同时访问同一个 List +- 没有同步机制会导致数据损坏 +- 可能出现脏读、丢失更新等问题 + +### 4. 测试困难 +- 单元测试时难以隔离 +- 一个测试可能影响另一个测试的结果 +- 需要手动清理共享状态 + +## 解决方案 + +### 方案 1:使用不可变集合 +```java +// 返回不可变列表 +public List
getArticles() { + return Collections.unmodifiableList(articles); +} +``` + +### 方案 2:防御性拷贝 +```java +// 创建副本 +public List
getArticlesCopy() { + return new ArrayList<>(articles); +} +``` + +### 方案 3:使用 Repository 模式 +```java +// 通过 Repository 管理,不直接暴露 List +public class ArticleRepository { + private List
articles = new ArrayList<>(); + + public void add(Article article) { } + public List
findAll() { + return new ArrayList<>(articles); // 返回副本 + } +} +``` + +## 总结 +共享引用虽然方便,但会带来数据一致性、封装性、线程安全等问题。 +最佳实践是: +1. 最小化共享 +2. 必要时使用防御性拷贝 +3. 使用不可变集合 +4. 通过接口/Repository 封装访问 + +(字数:约 450 字) diff --git a/W9/Main.java b/W9/Main.java new file mode 100644 index 0000000..73335ca --- /dev/null +++ b/W9/Main.java @@ -0,0 +1,25 @@ +package com.example.datacollect; + +import com.example.datacollect.command.HistoryCommand; +import com.example.datacollect.controller.CrawlerController; +import com.example.datacollect.model.Article; +import com.example.datacollect.view.ConsoleView; +import java.util.ArrayList; +import java.util.List; + +public class Main { + + public static void main(String[] args) { + ConsoleView view = new ConsoleView(); + List
articles = new ArrayList<>(); + HistoryCommand historyCommand = new HistoryCommand(); + CrawlerController controller = new CrawlerController(view, articles, historyCommand); + + view.printSuccess("Welcome to CLI Crawler (w9_1)! Type help for commands."); + while (true) { + String input = view.readLine(); + historyCommand.record(input); // 记录用户输入的命令 + controller.handle(input); + } + } +} diff --git a/W9/README.md b/W9/README.md new file mode 100644 index 0000000..f8af0e4 --- /dev/null +++ b/W9/README.md @@ -0,0 +1,17 @@ +# DataCollect 教学项目 — 最小可运行版本 + +这是一个最小可用的 Java CLI 演示工程,目标:打印帮助信息以验证运行环境。 + +构建: +```bash +mvn -q package +``` + +运行(示例): +```bash +java -jar target/datacollect-cli-0.1.0-jar-with-dependencies.jar --help +``` + +项目结构(最小): +- `src/main/java/com/example/datacollect/Main.java` — CLI 入口,打印帮助 +- `pom.xml` — Maven 构建配置,生成可执行 jar diff --git a/W9/W9.zip b/W9/W9.zip new file mode 100644 index 0000000..15cb0ec Binary files /dev/null and b/W9/W9.zip differ diff --git a/W9/W9ai协助记录.docx b/W9/W9ai协助记录.docx new file mode 100644 index 0000000..a01958f Binary files /dev/null and b/W9/W9ai协助记录.docx differ diff --git a/W9/pom.xml b/W9/pom.xml new file mode 100644 index 0000000..5599c10 --- /dev/null +++ b/W9/pom.xml @@ -0,0 +1,51 @@ + + 4.0.0 + com.example + datacollect-cli + 0.1.0 + + 11 + 11 + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 11 + 11 + UTF-8 + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + + com.example.datacollect.Main + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + +