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方法沒有依賴判斷,比較簡單的。

官網地址

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