我有一個庫,用於解析URL並提取一些數據。每個URL有一個類。要知道哪個類應該處理用戶提供的URL,我有下面的代碼。動態調用工廠中的正確實現
public class HostExtractorFactory {
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
switch (host) {
case HostExtractorABC.HOST_NAME:
return HostExtractorAbc.getInstance();
case HostExtractorDEF.HOST_NAME:
return HostExtractorDef.getInstance();
case HostExtractorGHI.HOST_NAME:
return HostExtractorGhi.getInstance();
default:
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
}
的問題是用戶請求多個URL被解析,這意味着我的switch語句越來越大。每次有人想出解析器時,我都必須修改我的代碼以包含它。
爲了達到這個目的,我決定創建一個映射並將它展示給它們,以便當它們的類寫入時,它們可以向工廠註冊自己,通過提供主機名和提取器到工廠。下面是實施這個想法的工廠。
public class HostExtractorFactory {
private static final Map<String, HostExtractor> EXTRACTOR_MAPPING = new HashMap<>();
private HostExtractorFactory() {
}
public static HostExtractor getHostExtractor(URL url)
throws URLNotSupportedException {
String host = url.getHost();
if(EXTRACTOR_MAPPING.containsKey(host)) {
return EXTRACTOR_MAPPING.get(host);
} else {
throw new URLNotSupportedException(
"The url provided does not have a corresponding HostExtractor: ["
+ host + "]");
}
}
public static void register(String hostname, HostExtractor extractor) {
if(StringUtils.isBlank(hostname) == false && extractor != null) {
EXTRACTOR_MAPPING.put(hostname, extractor);
}
}
}
而且用戶會用這樣的說法:
public class HostExtractorABC extends HostExtractor {
public final static String HOST_NAME = "www.abc.com";
private static class HostPageExtractorLoader {
private static final HostExtractorABC INSTANCE = new HostExtractorABC();
}
private HostExtractorABC() {
if (HostPageExtractorLoader.INSTANCE != null) {
throw new IllegalStateException("Already instantiated");
}
HostExtractorFactory.register(HOST_NAME, this);
}
public static HostExtractorABC getInstance() {
return HostPageExtractorLoader.INSTANCE;
}
...
}
我拍着我自己回來的時候,我意識到這不會有任何效果:用戶類在我收到URL時沒有加載,只有工廠,這意味着它們的構造函數永遠不會運行,並且地圖總是空的。所以我回到了繪圖板上,但希望得到這個工作的一些想法或另一種方法來擺脫這個煩人的開關語句。
小號
您可以使用**反射**,或者您必須列出所有已知或「想要可用」的類別,例如,一個配置文件...例如'org.reflections'是一個很好的輕量級庫,用於掃描類路徑。 – dedek
在一個簡單的文本文件中列出它們可以自行維護的類名,將工廠構造移動到一個靜態構造函數並在所有條目中使用'Class.forname'(https://stackoverflow.com/q/8100376/13075)在工廠初始化方法中的文件。 – Henrik
或者:引入它們應用於其類的註釋,並在工廠中掃描類路徑。 – Henrik