Search code examples
domain-driven-designjava-9java-platform-module-systemjava-module

Java 9 module and double dispatch in DDD


On some of my projects, I use the double dispatch mechanism to provide at run time a "view" of my infrastructure module to my domain module (Strengthening your domain: The double dispatch pattern). What I call 'modules' above is simply separate jar files where the dependency from service.jar->domain.jar is enforced at compile time only. Will I be able to have this working on java-9 if I define my service and domain as 'true' java 9 modules?

module domain
  L Fee.java
      L Payment recordPayment(double, BalanceCalculator)
  L BalanceCalculator.java
module service
  L BalanceCalculatorImpl.java // implements BalanceCalculator
      L double calculate(Fee fee) //call fee.recordPayment(amount,this)

Solution

  • Yes that is possible. Here are some things to consider:

    1. The module domain needs to export the package containing Fee. Possibly to everyone but at least to service.
    2. The module service will have to require domain as BalanceCalculatorImpl has to access BalanceCalculator since it implements it.
    3. It looks like clients of service need to know about domain as well, which is a textbook case for implied readability.
    4. In a simple setup either service or some third module will have to instantiate BalanceCalculatorImpl and pass it to Fee, this can not happen in domain or it would create a cyclic dependency.
    5. A more advanced solution would be services, where all code that can access BalanceCalculator, even inside domain, can get hold of all its implementations.

    Taking all of these into account, this is what the two module declarations might look like:

    module com.example.domain {
        // likely some requires clauses
    
        // export packages containing Fee and BalanceCalculator
        exports com.example.domain.fee;
        exports com.example.domain.balance;
    }
    
    module com.example.service {
        requires public com.example.domain;
        // likely some more requires clauses
    
        // expose BalanceCalculatorImpl as a service,
        // which makes it unnecessary to export the containing package
        provides com.example.domain.balance.BalanceCalculator
            with com.example.service.balance.BalanceCalculatorImpl;
    }
    

    Then every module that likes to use BalanceCalculator can declare it in its module declaration with uses com.example.domain.balance.BalanceCalculator and get instances of that using Java's ServiceLoader.

    You can find more practical applications of the module system (particularly for services] in a demo I created.

    (Note: The answer was revised after this exchange.)