JODConverter框架所用的设计模式

JODConverter 是Java OpenDocument文件转换器库,可以进行许多文件格式的转换。它依赖于OpenOffice或LibreOffice 提供的服务来进行转换,它能将Microsoft Office文档(Word,Excel,PowerPoint)转换为PDF格式

在项目中使用了JODConverter。简单了解下源码,其中有几个设计模式,本篇文章分享下建造者模式。

设计模式介绍

建造者模式简单说就是创建一个对象。那创建一个对象什么要一个设计模式呢?如果一个类中有很多属性,创建对象时可以通过构造函数传参或通过set方法设置。为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。通过构造函数传参数多了很头痛。如果类的属性之间有一定的依赖关系或者约束条件通过set方式设置也很头痛。于是就有了建造者模式,来解决对象有很多参数的问题。

代码演示

本地使用的版本为:


        <dependency>
            <groupId>org.jodconverter</groupId>
            <artifactId>jodconverter-core</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.jodconverter</groupId>
            <artifactId>jodconverter-local</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.libreoffice</groupId>
            <artifactId>ridl</artifactId>
            <version>5.4.2</version>
        </dependency>

按照官方文档例子,常规操作流程如下,先是创建一个OfficeManager服务。启动,转调用JodConverter.convert转换文件,最后停止服务。

File inputFile = new File("document.doc");
File outputFile = new File("document.pdf");

// Create an office manager using the default configuration.
// The default port is 2002. Note that when an office manager
// is installed, it will be the one used by default when
// a converter is created.
final LocalOfficeManager officeManager = LocalOfficeManager.install(); 
try {

    // Start an office process and connect to the started instance (on port 2002).
    officeManager.start();

    // Convert
    JodConverter
             .convert(inputFile)
             .to(outputFile)
             .execute();
} finally {
    // Stop the office process
    OfficeUtils.stopQuietly(officeManager);
}

例子中是通过LocalOfficeManager.install()方法创建一个默认配置的LocalOfficeManager。那么创建一个LocalOfficeManager需要如下配置。

   private String[] pipeNames; 
   private int[] portNumbers; //服务端口
   private File officeHome; // libreaoffice or openoffice 安装路径
   private ProcessManager processManager;
   private String[] runAsArgs;
   private File templateProfileDir; //转换的临时文件存放路径
   private boolean killExistingProcess;
   private long processTimeout;  //转换任务超时
   private long processRetryInterval;
   private int maxTasksPerProcess;
   private boolean disableOpengl;

LocalOfficeManager主要代码结构如下。主要保留建造者模式代码。

public final class LocalOfficeManager extends AbstractOfficeManagerPool {

  
  /**
   * Creates a new builder instance.
   *
   * @return A new builder instance.
   */
  public static Builder builder() {
    return new Builder();
  }

 

  private LocalOfficeManager(
      final OfficeUrl[] officeUrls, final OfficeProcessManagerPoolConfig config) {
    super(officeUrls.length, config);

    this.officeUrls = Arrays.copyOf(officeUrls, officeUrls.length);
  }

 

  /**
   * LocalOfficeManager 构造类
   *
   * @see LocalOfficeManager
   */
  public static final class Builder extends AbstractOfficeManagerPoolBuilder<Builder> {

    // LocalOfficeManager 对象参数值
    private String[] pipeNames;
    private int[] portNumbers;
    private File officeHome;
    private ProcessManager processManager;
    private String[] runAsArgs;
    private File templateProfileDir;
    private boolean killExistingProcess = OfficeProcessConfig.DEFAULT_KILL_EXISTING_PROCESS;

    // 默认参数值
    private long processTimeout = OfficeProcessManagerConfig.DEFAULT_PROCESS_TIMEOUT;
    private long processRetryInterval = OfficeProcessManagerConfig.DEFAULT_PROCESS_RETRY_INTERVAL;
    private int maxTasksPerProcess = OfficeProcessManagerConfig.DEFAULT_MAX_TASKS_PER_PROCESS;
    private boolean disableOpengl = OfficeProcessManagerConfig.DEFAULT_DISABLE_OPENGL;
    
    // Private ctor so only LocalOfficeManager can initialize an instance of this builder.
    private Builder() {
      super();
    }
      
      
      //返回创建好的LocalOfficeManager
      public LocalOfficeManager build() {

      // 设置默认参数
      if (officeHome == null) {
        officeHome = LocalOfficeUtils.getDefaultOfficeHome();
      }
		// 设置默认参数
      if (workingDir == null) {
        workingDir = new File(System.getProperty("java.io.tmpdir"));
      }
	  // 设置默认参数
      if (processManager == null) {
        processManager = LocalOfficeUtils.findBestProcessManager();
      }

      // Build the office URLs
      final OfficeUrl[] officeUrls = LocalOfficeUtils.buildOfficeUrls(portNumbers, pipeNames);
          
	  //OfficeProcessManagerPoolConfig 是创建LocalOfficeManager对象需要传的参数
      //参数都是通过 LocalOfficeManager.builder().officeHome("/user/aaa")方式传个builder。
      final OfficeProcessManagerPoolConfig config =
          new OfficeProcessManagerPoolConfig(officeHome, workingDir, processManager);
      config.setRunAsArgs(runAsArgs);
      config.setTemplateProfileDir(templateProfileDir);
      config.setKillExistingProcess(killExistingProcess);
      config.setProcessTimeout(processTimeout);
      config.setProcessRetryInterval(processRetryInterval);
      config.setMaxTasksPerProcess(maxTasksPerProcess);
      config.setDisableOpengl(disableOpengl);
      config.setTaskExecutionTimeout(taskExecutionTimeout);
      config.setTaskQueueTimeout(taskQueueTimeout);
	 //LocalOfficeManager 需要OfficeProcessManagerPoolConfig,OfficeUrl两个构造参数。 
      final LocalOfficeManager manager = new LocalOfficeManager(officeUrls, config);
      if (install) {
        InstalledOfficeManagerHolder.setInstance(manager);
      }
      return manager;
    }


    /**
     * 设置参数。返回是当前builder对象
     * @return This builder instance.
     */
    public Builder pipeNames(final String... pipeNames) {

      Validate.isTrue(
          pipeNames != null && pipeNames.length > 0, "The pipe name list must not be empty");
      this.pipeNames = ArrayUtils.clone(pipeNames);
      return this;
    }

    /**
    * 设置参数。返回是当前builder对象
     * Specifies the port numbers that will be use to communicate with office. An instance of office
     * will be launched for each port number.
     *
     * @param portNumbers The port numbers to use.
     * @return This builder instance.
     */
    public Builder portNumbers(final int... portNumbers) {

      Validate.isTrue(
          portNumbers != null && portNumbers.length > 0, "The port number list must not be empty");
      this.portNumbers = ArrayUtils.clone(portNumbers);
      return this;
    }
     ......//省略不是主要的
  }
}

可以看出LocalOfficeManager里有个内部类Builder,Builder类差不多像是平时使用Entity VO,包括了参数和set方法。这里的set方法返回时当前对象。

LocalOfficeManager构造方法时私有的,外部不能直接new。构造方法也是私有的,不能直接new。所有Builder类的build方法是真正创建对象的地方。

比如不想使用默认方式创建LocalOfficeManager。可以通过如下方式,链式设值创建

//指定officehome和应用端口
OfficeManager officeManager =   LocalOfficeManager.builder().officeHome(officeHome).portNumbers(123,456).install().build();

Builder.buid方法没有依赖判断,比较简单的。

官网地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章