0
\$\begingroup\$

I've a class called MassIndexer.java (on GitHub) and it uses chained invocation for building a batch job. Each method assigns a property of this job and finally the job will be started using method MassIndexer#start(). Here's an example for Java EE:

long executionId = new MassIndexer()
        .addRootEntities(Company.class, Employee.class)
        .start();

According to different environments, the requirement is different. Some methods are required in Java SE while all of them are optional in Java EE. If users use MassIndexer under Java SE and they forget to set the properties through those required methods, the job will fail. These required methods on Java SE are:

  • isJavaSE(boolean)
  • entityManagerFactory(EntityManagerFactory)
  • jobOperator(JobOperator)

Here's another example for Java SE:

long executionId = new MassIndexer()
        .addRootEntities(Company.class, Employee.class)
        .isJavaSE(true)
        .entityManagerFactory(emf)
        .jobOperator(jobOperator)
        .start();

However, the design of this class in not clear: people don't know which method is required and which isn't. The only way to know it is to read the documentation. And I'm wondering how can I improve the design of this class, so that people can easily understand what to do and how to do. For example, should this class be split into MassIndexerEE and MassIndexerSE? Should it be refactored into a builder class, e.g. BatchIndexingJobBuilder?

And there's no order or logic among these methods. You can call foo() then bar(), but bar() then foo() works too. Properties are used for configurations based on

  • selection of class types (about persistence)
  • database interaction (about persistence)
  • parallel processing (about job)
  • checkpoing algorithm (about job)

Someone must be confused when using this class, so I'm seeking advice. Every review is welcomed.

\$\endgroup\$
1
\$\begingroup\$

Make a second level Builder class

long executionId = new MassIndexer()
        .addRootEntities(Company.class, Employee.class)
        .javaSE()
        .entityManagerFactory(emf)
        .jobOperator(jobOperator)
        .start();

long executionId = new MassIndexer()
        .addRootEntities(Company.class, Employee.class)
        .javaEE()
        .start();

class MassIndexer
    MassIndexer addRootEntities(Class<?>...)
    SEBuilder javaSE()
    EEBuilder javaEE()

class MassIndexer.SEBuilder
    long start()
    SEBuilder entityManagerFactory(EntityManagerFactory)
...
  • I am not that happy with the name and using a constructor for MassIndexer
  • addRootEntities might go in the "constructor"
  • javaSE/EE maybe standalone/server or container?
\$\endgroup\$
1
\$\begingroup\$

Try to avoid allowing the invocation chain to go from a valid object to an invalid object. Your setJavaSE allows that.

Instead you can make a method configureJavaSE(EntityManagerFactory, JobOperator) which takes all the required configuration items for setting javaSE to true.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.