Como resolver dependências de pacotes circulares

11

Estou refatorando uma grande base de código em que a maioria das classes está localizada em um pacote. Para uma melhor modularidade, estou criando subpacotes para cada funcionalidade.

Lembro-me de aprender em algum lugar que um gráfico de dependência de pacote não deve ter loops, mas não sei como resolver o seguinte problema: Figureestá no pacote figure, Layoutestá no pacote layout, Layoutrequer a figura para executar o layout, portanto, o pacote layoutdepende do pacote figure. Mas, por outro lado, a Figurepode conter outros Figures dentro dele, tendo o seu próprio Layout, o que torna o pacote figuredependente do pacote layout.

Eu tenho algumas soluções, como criar uma Containerinterface que Figureimplementa e colocá-lo no Layoutpacote. Esta é uma boa solução? Alguma outra possibilidade?

obrigado

vainolo
fonte
É módulos (por exemplo, Jars diferentes) não podem ter dependências circulares. Os pacotes CAN e geralmente têm dependências circulares, desde que pertençam ao mesmo módulo.
Lorus
@lorus Portanto, este não é um problema de design?
vainolo
2
Não não é. Os pacotes normalmente são apenas espaços de nomes. Isso pode mudar apenas quando usado para outra coisa, por exemplo, para alterar a visibilidade do conteúdo no ambiente OSGi. Não se incomode de outra maneira.
Lorus
1
Observe que muitas autoridades condenam dependências cíclicas e, às vezes, por um bom motivo, mas antes de refatorar cegamente, verifique se um desses motivos realmente se aplica a você. Se a estrutura do pacote não estiver causando problemas e você não puder, em sã consciência, ver por que isso aconteceria no futuro, não alteraria algo tão fundamental apenas para satisfazer os valores arquitetônicos abstratos.
22713 Kilian Foth

Respostas:

9

Você deve pensar em Inversão do controle

Você basicamente define uma interface para a sua, Layoutlocalizada em algum lugar próximo à sua classe Layout em um pacote próprio, para ter um pacote de implementação e um pacote de interface pública - por exemplo, chame-o Layoutable(não sei se esse é o inglês adequado). Agora - o layout não implementará essa interface, mas a Figureclasse. Da mesma forma, você criaria uma interface para a Figura, Drawablepor exemplo.

então

my.public.package.Layoutable
my.implementation.package.Layout
my.public.package.Drawable
my.implementation.package.Figure

Agora - a figura implementa Layoutable e, portanto, pode ser usada pelo Layout e (ainda não tenho certeza se é isso que você queria) - o layout implementa Drawable e pode ser desenhado em uma figura. O ponto é que a classe que expõe algum serviço o torna disponível por uma interface (aqui: Layout e Layoutable) - a classe que deseja usar esse serviço precisa implementar a interface.

Então você teria algo como um objeto criador que une os dois. Assim, o criador teria uma dependência Layoutbem como Figure, mas Layoute Figureeles próprios seria independente.

Essa é a ideia aproximada.

Uma excelente fonte de soluções para esses problemas é o livro Java Application Architecture de Kirk Knoernschild.

michael_s
fonte
Não é o mesmo que a Containerinterface sugerida na pergunta?
vaughandroid
Sim - e não - eu não colocaria os dois no mesmo pacote que afirmei. E não havia muita teoria por trás disso. E, neste caso, não é suficiente fazê-lo de um lado, você terá que fazê-lo de ambos os lados. Bem?
22613 Michael
Opa, eu perdi a parte da pergunta original sobre Containero mesmo pacote que Layout. Isso não funcionaria, enquanto sua solução funcionaria.
vaughandroid
ah - ok - I parecia ter perdido a parte com o Container embora quando eu estava cortando - deveria ter chamado ele Container;)
michael_s
0

Eu não sou muito claro sobre o que Figureé, mas talvez deva estar no mesmo pacote que Layout?

Sua Containersolução de interface proposta não funcionaria - a menos que você coloque a Containerinterface em um terceiro pacote, você ainda terá uma dependência circular entre os dois pacotes. Veja a resposta de michael_s para algo que funcione.

Outra coisa, como outros já mencionaram - provavelmente nunca será um problema. Você só vai ter problemas no futuro se Figuree Layoutquer estar em separado módulos . Você pode lidar com isso se e quando isso for necessário, mas, como as duas classes parecem muito relacionadas, isso parece altamente improvável.

vaughandroid
fonte