Opiniões para uma arquitetura em fluent interfaces

Estou com um projeto pessoal(por enquanto) de fazer um sistema de cadastro e consulta de pessoas e itens relacionados a elas. Ele é baseado num existente, que é bem geral, por exemplo, se tem cadastro de empresas, também tem os sócios, que por sua vez tem endereços de correspondência, estes endereços tem municípios, estados, e por aí vai, é um sistema com vários subsistemas.

A idéia é fazer algo que consulte tudo isso, um grande query builder, para os desenvolvedores usarem em suas IDEs, aproveitando a tipagem estática do Java para facilitar a montagem. O sistema em si é um provedor de dados para outros sistemas.

As dúvidas são sobre como montar tudo, sintaxe, o fechamento da construção para executar as consultas, etc.

consultarPessoas.porCPF(cpf).comEndereçoDeCorrespondência().comEndereçoDeMoradia()

Meu primeiro problema é com a conjunção “com”, normalmente usadas para filtrar a consulta. O comportamento que quero é que ele traga também estes dois endereços já preenchidos, e também traga a pessoa caso ela não tenha esses atributos, que são opcionais.

O que pensei não usar esse “com” desta forma:

consultarPessoas.porCPF(cpf).trazendoEndereçoDeCorrespondência().trazendoEndereçoDeMoradia()

Também achei o trazendo meio grande demais, pensei outra forma.

consultarPessoas.porCPF(cpf).trazendo(EndereçoDeCorrespondência, EndereçoDeMoradia, ...) //eu teria que publicar estes atributos de alguma forma

Ou

consultarPessoas.porCPF(cpf).trazendo().EndereçoDeCorrespondência().e().EndereçoDeMoradia() // estilo Hamcrest?

Daí p/ frente eu começo a pegar um pouco de raiva desses parênteses obrigatórios.

A dúvida é como parar, e como aplicar atributos que só pertencem à um atributo(municipio é parte de endereço, não de pessoa), e ainda manter o contexto original da consulta.

Outra coisa que percebo aqui, em contraste com a maneira que estou pensando, eu não estou dando a opção ou facilitando elas implementarem as coisas com lazy fetch. É válido fazer um algo inteiramente eager? Aliás acho fazer um lazy fetch só seria possível se os outros sistemas tivessem um Entity Manager, e mesmo que tivessem, como o gerenciador de um sistema conversa com o outro?

Preferências, brainstorms?

Minha sugestão é usar o varargs com um enum

consultarPessoas.porCPF(cpf).trazendo(Operador.E, Endereco.EndereçoDeCorrespondência, Endereco.EndereçoDeMoradia);

public Pessoa trazendo(Operador tipo, Endereco... end){...}