在软件开发中利用反射机制来减少包依赖

前端之家收集整理的这篇文章主要介绍了在软件开发中利用反射机制来减少包依赖前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

MD2File是我以前写的一个开源软件,主要功能是“将markdown语法的文档内容,导出为word,pdf,HTML等的文件;也支持markdown转HTML文本”。

其中,导出为word文档,需要依赖POI,导出pdf需要依赖iText。其中,iText支持4.x版本和5.x版本。这里就涉及到一个问题,我还是举例子说明下。

如果用户只需要一个功能,导出word文档功能。那用户总不能为了这个功能,而引入一个无关的iText包吧。反之也是,用户要导出PDF功能,却需要引入POI包。

但是,一开始我的代码还真是这样,如果不引入,会导致ClassNotFound异常,致使编译不通过,无法使用。

设计上,我是通过一个工厂类,然后根据需要的文件名后缀,来生产不同的文档Builder。代码一开始是这么写的。

  1. public class BuilderFactory{
  2. public static Decorator build(String ext) {
  3. DecoratorBuilder decoratorBuilder;
  4. if(ext.equalsIgnoreCase("docx")){
  5. decoratorBuilder = new DocxDecoratorBuilder();
  6. }else if(ext.equalsIgnoreCase("doc")){
  7. decoratorBuilder = new DocDecoratorBuilder();
  8. }else if(ext.equalsIgnoreCase("pdf")){
  9. if(itextVersion==PDF_ITEXT_5X){
  10. decoratorBuilder = new PDFDecoratorBuilder5x();
  11. }else{
  12. decoratorBuilder = new PDFDecoratorBuilder4x();;
  13. }
  14. }else if(ext.equalsIgnoreCase("html") ||ext.equalsIgnoreCase("htm")){
  15. decoratorBuilder = new HTMLDecoratorBuilder();
  16. }else{
  17. throw new RuntimeException("请确认输出的文档为docx,doc,pdf,html的文档格式");
  18. }
  19. Decorator decorator = decoratorBuilder.build();
  20. return decorator;
  21. }
  22. }

这么写很大的问题,就是这个BuilderFactory依赖于DocxDecoratorBuilder,DocDecoratorBuilder,PDFDecoratorBuilder5x,PDFDecoratorBuilder4x,HTMLDecoratorBuilder。而这几个Bulder又各自依赖于不同的第三方jar包。假设我没引入POI包,DocxDecoratorBuilder,DocDecoratorBuilder报错,BuilderFactory就编译不通过了。

于是,就导致了我们一开始说到的问题。

如果用户只需要一个功能,导出word文档功能。那用户总不能为了这个功能,而引入一个无关的iText包吧。反之也是,用户要导出PDF功能,却需要引入POI包。

而且,还有个问题,如果用户需要导出的是PDF文档,那我怎么知道用户用的是iText 4.x包还是iText 5.x包?

这时候是用Java的反射机制的好时机!先看改造后的代码

  1. public class BuilderFactory{
  2. private static final int PDF_ITEXT_5X = 5;
  3. private static final int PDF_ITEXT_4X = 4;
  4.  
  5. private static int itextVersion = PDF_ITEXT_4X;
  6. /**
  7. * 检查iText的版本
  8. */
  9. static{
  10. String doc5x = "com.itextpdf.text.Document";
  11. // String doc4x = "com.lowagie.text.Document";
  12. try {
  13. Class.forName(doc5x);
  14. itextVersion = PDF_ITEXT_5X;
  15. } catch (ClassNotFoundException e) {
  16. itextVersion = PDF_ITEXT_4X;
  17. }
  18. }
  19. private static DecoratorBuilder initDecoratorBuilder(String className){
  20. try {
  21. @SuppressWarnings("rawtypes")
  22. Class clazz = Class.forName(className);
  23. return (DecoratorBuilder)clazz.newInstance();
  24. } catch (InstantiationException e) {
  25. e.printStackTrace();
  26. } catch (IllegalAccessException e) {
  27. e.printStackTrace();
  28. } catch (ClassNotFoundException e) {
  29. e.printStackTrace();
  30. }
  31. return null;
  32. }
  33. private static final String DOC_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.DocDecoratorBuilder";
  34. private static final String DOCX_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.DocxDecoratorBuilder";
  35. private static final String PDF_4X_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.PDFDecoratorBuilder4x";
  36. private static final String PDF_5X_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.PDFDecoratorBuilder5x";
  37. private static final String HTML_BUILDER_CLASS_NAME = "net.oschina.md2.export.builder.HTMLDecoratorBuilder";
  38. public static Decorator build(String ext) {
  39. DecoratorBuilder decoratorBuilder;
  40. if(ext.equalsIgnoreCase("docx")){
  41. decoratorBuilder = initDecoratorBuilder(DOCX_BUILDER_CLASS_NAME);
  42. }else if(ext.equalsIgnoreCase("doc")){
  43. decoratorBuilder = initDecoratorBuilder(DOC_BUILDER_CLASS_NAME);
  44. }else if(ext.equalsIgnoreCase("pdf")){
  45. if(itextVersion==PDF_ITEXT_5X){
  46. decoratorBuilder = initDecoratorBuilder(PDF_5X_BUILDER_CLASS_NAME);
  47. }else{
  48. decoratorBuilder = initDecoratorBuilder(PDF_4X_BUILDER_CLASS_NAME);
  49. }
  50. }else if(ext.equalsIgnoreCase("html") ||ext.equalsIgnoreCase("htm")){
  51. decoratorBuilder = initDecoratorBuilder(HTML_BUILDER_CLASS_NAME);
  52. }else{
  53. throw new RuntimeException("请确认输出的文档为docx,doc,pdf,html的文档格式");
  54. }
  55. Decorator decorator = decoratorBuilder.build();
  56. return decorator;
  57. }
  58. }

现在,代码里我们只是先定义了各个Builder实现的包路径,然后通过

Class clazz = Class.forName(className);
(DecoratorBuilder)clazz.newInstance();

来初始化Builder,这样就解决了BuilderFactory依赖过重的问题。用户需要用什么功能,就只需要引入相应的jar包即可。如果用导出HTML功能或者markdown转HTML功能,甚至任何其它包都不需要。

新的代码还使用了个小技巧,来检查用户使用的iText版本问题。代码就是下面这段

  1. static{
  2. String doc5x = "com.itextpdf.text.Document";
  3. // String doc4x = "com.lowagie.text.Document";
  4. try {
  5. Class.forName(doc5x);
  6. itextVersion = PDF_ITEXT_5X;
  7. } catch (ClassNotFoundException e) {
  8. itextVersion = PDF_ITEXT_4X;
  9. }
  10. }

以上,就是本人在代码开发中,使用反射来减少包依赖的小技巧。希望对看到本文的你有所帮助:-)

对了,如果刚好有markdown转其它文档的功能,可以看下MD2File这个小软件,谢谢~

猜你在找的设计模式相关文章