在设计中加入一个顶层接口是有益的,特别是当您希望实现统一的接口来处理所有类型的排行榜数据时。这样做可以提供更好的灵活性和扩展性,同时保持代码的整洁和易于维护。
设计概述
- 接口 : 定义一个
RankingDataCollector
接口,它定义了所有数据收集器应该遵循的方法签名。 - 抽象基类 : 定义一个抽象基类
RankingPageParser
,它包含所有解析器共有的方法和属性。 - 具体解析器 : 每个数据来源都有一个对应的子类,如
ToutiaoRankingParser
、WeiboRankingParser
等。 - 工厂模式: 使用工厂模式来根据数据来源创建相应的解析器实例。
java
classDiagram
class RankingDataCollector{
+List<String> collectData(String url)
}
class RankingPageParser{
+String url
+Document parsePage()
abstract +List<String> extractTitles()
}
class ToutiaoRankingParser{
+RankingPageParser(url: String)
+List<String> extractTitles()
}
class WeiboRankingParser{
+RankingPageParser(url: String)
+List<String> extractTitles()
}
class RankingParserFactory{
+static RankingPageParser createParser(String platform, String url)
}
RankingPageParser <|-- ToutiaoRankingParser
RankingPageParser <|-- WeiboRankingParser
RankingDataCollector <|-- ToutiaoRankingParser
RankingDataCollector <|-- WeiboRankingParser
Java 实现示例
1. 接口 RankingDataCollector
java
public interface RankingDataCollector {
List<String> collectData(String url);
}
2. 抽象基类 RankingPageParser
java
public abstract class RankingPageParser implements RankingDataCollector {
protected String url;
public RankingPageParser(String url) {
this.url = url;
}
public Document parsePage() throws IOException {
return Jsoup.connect(url).get();
}
public abstract List<String> extractTitles();
@Override
public List<String> collectData(String url) {
this.url = url;
return extractTitles();
}
}
3. 具体解析器
java
public class ToutiaoRankingParser extends RankingPageParser {
public ToutiaoRankingParser(String url) {
super(url);
}
@Override
public List<String> extractTitles() {
List<String> titles = new ArrayList<>();
try {
Document doc = parsePage();
Elements titleWraps = doc.select(".list-container .title-wrap");
for (Element titleWrap : titleWraps) {
String titleText = titleWrap.text();
titles.add(titleText);
}
} catch (IOException e) {
e.printStackTrace();
}
return titles;
}
}
public class WeiboRankingParser extends RankingPageParser {
public WeiboRankingParser(String url) {
super(url);
}
@Override
public List<String> extractTitles() {
List<String> titles = new ArrayList<>();
try {
Document doc = parsePage();
Elements titleElements = doc.select(".weibo-rank .rank-item .title");
for (Element titleElement : titleElements) {
String titleText = titleElement.text();
titles.add(titleText);
}
} catch (IOException e) {
e.printStackTrace();
}
return titles;
}
}
4. 工厂模式
java
public class RankingParserFactory {
public static RankingPageParser createParser(String platform, String url) {
switch (platform) {
case "toutiao":
return new ToutiaoRankingParser(url);
case "weibo":
return new WeiboRankingParser(url);
default:
throw new IllegalArgumentException("Unsupported platform: " + platform);
}
}
}
5. 使用示例
java
public class Main {
public static void main(String[] args) {
String url = "https://example.com/toutiao-ranking";
RankingDataCollector collector = RankingParserFactory.createParser("toutiao", url);
List<String> titles = collector.collectData(url);
System.out.println("Collected Titles: " + titles);
}
}
通过这样的设计,您可以轻松地添加新的数据来源或更改现有数据源的解析逻辑,只需实现 RankingPageParser
抽象类或扩展 RankingDataCollector
接口即可。这种设计模式使得代码更加模块化和易于维护。