Search code examples
javaoopdomain-driven-designcompositevisitor-pattern

DDD - Composite Aggregate Serialization - design problem


I'm trying to apply DDD to one Java project. This is the problem I stumbled upon:

In the domain, I have an Aggregate that is implemented using Composite OOP pattern. Methods on this aggregate produce some domain objects that need to be serialized and sent over the wire. These are options I thought about:

  1. In Application Service part of my domain I'm taking aggregate, call it's methods, and try to serialize results to DTO. In order to serialize it to DTO I have to use instanceof to check if current node is Composite or Child and continue with serialization. Since instanceof is code smell (as I read that it breaks Open/Close principle etc.), I decided to try to use Visitor pattern.

  2. In order to apply Visitor pattern, my Composite Aggregate has to implement Visitor which will return DTO's and then DTO's become part of domain layer - which is also not good design (since domain should contain only domain concepts, and DTO's are not part of that). DTO serialization is only technical detail that should not go to domain layer.

Is there any other solution that is not in collision with these design principles?

Is there a way to simulate dynamic binding in java for overloaded methods (other than instanceof - since this would solve my problem with option 1)?


Solution

  • If the Visitor has a generic return type, then the visited classes are not coupled to that type.

    public interface Node {
        <T> T accept(NodeVisitor<T> visitor);
    }
    
    public class ANode implements Node {
        @Override
        public <T> T accept(NodeVisitor<T> visitor) {
            return visitor.visit(this);
        }
    }
    
    public class BNode implements Node {
        @Override
        public <T> T accept(NodeVisitor<T> visitor) {
            return visitor.visit(this);
        }
    }
    
    public interface NodeVisitor<T> {
        T visit(ANode aNode);
        T visit(BNode bNode);
    }
    
    public class DtoNodeVisitor implements NodeVisitor<DTO> {
        @Override
        public DTO visit(ANode aNode) {
            return new DTO(); //use ANode to build this.
        }
        @Override
        public DTO visit(BNode bNode) {
            return new DTO(); //use BNode to build.
        }
    }
    

    ANode and BNode have no knowledge of DTO here.