MD2File 是我之前寫的一個開源軟件,主要功能是「將markdown語法的文檔內容,導出爲word,pdf,HTML等的文件;也支持markdown轉HTML文本」。html
其中,導出爲word文檔,須要依賴POI,導出pdf須要依賴iText。其中,iText支持4.x版本和5.x版本。這裏就涉及到一個問題,我仍是舉例子說明下。java
若是用戶只須要一個功能,導出word文檔功能。那用戶總不能爲了這個功能,而引入一個無關的iText包吧。反之也是,用戶要導出PDF功能,卻須要引入POI包。git
可是,一開始個人代碼還真是這樣,若是不引入,會致使ClassNotFound異常,導致編譯不經過,沒法使用。markdown
設計上,我是經過一個工廠類,而後根據須要的文件名後綴,來生產不一樣的文檔Builder。代碼一開始是這麼寫的。ui
public class BuilderFactory{ public static Decorator build(String ext) { DecoratorBuilder decoratorBuilder; if(ext.equalsIgnoreCase("docx")){ decoratorBuilder = new DocxDecoratorBuilder(); }else if(ext.equalsIgnoreCase("doc")){ decoratorBuilder = new DocDecoratorBuilder(); }else if(ext.equalsIgnoreCase("pdf")){ if(itextVersion==PDF_ITEXT_5X){ decoratorBuilder = new PDFDecoratorBuilder5x(); }else{ decoratorBuilder = new PDFDecoratorBuilder4x();; } }else if(ext.equalsIgnoreCase("html") ||ext.equalsIgnoreCase("htm")){ decoratorBuilder = new HTMLDecoratorBuilder(); }else{ throw new RuntimeException("請確認輸出的文檔爲docx,doc,pdf,html的文檔格式"); } Decorator decorator = decoratorBuilder.build(); return decorator; } }
這麼寫很大的問題,就是這個BuilderFactory依賴於DocxDecoratorBuilder,DocDecoratorBuilder,PDFDecoratorBuilder5x,PDFDecoratorBuilder4x,HTMLDecoratorBuilder。而這幾個Bulder又各自依賴於不一樣的第三方jar包。假設我沒引入POI包,DocxDecoratorBuilder,DocDecoratorBuilder報錯,BuilderFactory就編譯不經過了。.net
因而,就致使了咱們一開始說到的問題。設計
若是用戶只須要一個功能,導出word文檔功能。那用戶總不能爲了這個功能,而引入一個無關的iText包吧。反之也是,用戶要導出PDF功能,卻須要引入POI包。code
並且,還有個問題,若是用戶須要導出的是PDF文檔,那我怎麼知道用戶用的是iText 4.x包仍是iText 5.x包?htm
這時候是用Java的反射機制的好時機!先看改造後的代碼:開發
public class BuilderFactory{ private static final int PDF_ITEXT_5X = 5; private static final int PDF_ITEXT_4X = 4; private static int itextVersion = PDF_ITEXT_4X; /** * 檢查iText的版本 */ static{ String doc5x = "com.itextpdf.text.Document"; // String doc4x = "com.lowagie.text.Document"; try { Class.forName(doc5x); itextVersion = PDF_ITEXT_5X; } catch (ClassNotFoundException e) { itextVersion = PDF_ITEXT_4X; } } private static DecoratorBuilder initDecoratorBuilder(String className){ try { @SuppressWarnings("rawtypes") Class clazz = Class.forName(className); return (DecoratorBuilder)clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } private static final String DOC_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.DocDecoratorBuilder"; private static final String DOCX_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.DocxDecoratorBuilder"; private static final String PDF_4X_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.PDFDecoratorBuilder4x"; private static final String PDF_5X_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.PDFDecoratorBuilder5x"; private static final String HTML_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.HTMLDecoratorBuilder"; public static Decorator build(String ext) { DecoratorBuilder decoratorBuilder; if(ext.equalsIgnoreCase("docx")){ decoratorBuilder = initDecoratorBuilder(DOCX_BUILDER_CLASS_NAME); }else if(ext.equalsIgnoreCase("doc")){ decoratorBuilder = initDecoratorBuilder(DOC_BUILDER_CLASS_NAME); }else if(ext.equalsIgnoreCase("pdf")){ if(itextVersion==PDF_ITEXT_5X){ decoratorBuilder = initDecoratorBuilder(PDF_5X_BUILDER_CLASS_NAME); }else{ decoratorBuilder = initDecoratorBuilder(PDF_4X_BUILDER_CLASS_NAME); } }else if(ext.equalsIgnoreCase("html") ||ext.equalsIgnoreCase("htm")){ decoratorBuilder = initDecoratorBuilder(HTML_BUILDER_CLASS_NAME); }else{ throw new RuntimeException("請確認輸出的文檔爲docx,doc,pdf,html的文檔格式"); } Decorator decorator = decoratorBuilder.build(); return decorator; } }
如今,代碼裏咱們只是先定義了各個Builder實現的包路徑,而後經過
Class clazz = Class.forName(className);
(DecoratorBuilder)clazz.newInstance();
來初始化Builder,這樣就解決了BuilderFactory 依賴太重的問題。用戶須要用什麼功能,就只須要引入相應的jar包便可。若是用導出HTML功能或者markdown轉HTML功能,甚至任何其它包都不須要。
新的代碼還使用了個小技巧,來檢查用戶使用的iText版本問題。代碼就是下面這段
static{ String doc5x = "com.itextpdf.text.Document"; // String doc4x = "com.lowagie.text.Document"; try { Class.forName(doc5x); itextVersion = PDF_ITEXT_5X; } catch (ClassNotFoundException e) { itextVersion = PDF_ITEXT_4X; } }
以上,就是本人在代碼開發中,使用反射來減小包依賴的小技巧。但願對看到本文的你有所幫助:-)
對了,若是恰好有markdown轉其它文檔的功能,能夠看下MD2File 這個小軟件,謝謝~