A idéia básica por trás da OOP é que dados e comportamento (com base nesses dados) são inseparáveis e são acoplados à idéia de um objeto de uma classe. O objeto possui dados e métodos que funcionam com esse (e outros dados). Obviamente, pelos princípios da OOP, objetos que são apenas dados (como estruturas C) são considerados um antipadrão.
Por enquanto, tudo bem.
O problema é que notei que meu código parece estar indo cada vez mais na direção desse antipadrão ultimamente. Parece-me que quanto mais eu tento obter informações ocultas entre classes e designs fracamente acoplados, mais minhas classes passam a ser uma mistura de dados puros sem classes de comportamento e todo comportamento sem classes de dados.
Geralmente, eu desenho classes de uma maneira que minimize a conscientização da existência de outras classes e minimize o conhecimento das interfaces de outras classes. Eu imponho isso especialmente de cima para baixo, as classes de nível inferior não conhecem as classes de nível superior. Por exemplo:
Suponha que você tenha uma API geral de jogo de cartas. Você tem uma aula Card. Agora essa Cardclasse precisa determinar a visibilidade para os jogadores.
Uma maneira é ter boolean isVisible(Player p)na Cardaula.
Outra é ter boolean isVisible(Card c)na Playeraula.
Não gosto da primeira abordagem em particular, pois concede conhecimento sobre Playerclasse de nível superior a uma Cardclasse de nível inferior .
Em vez disso, optei pela terceira opção, onde temos uma Viewportclasse que, dada ae Playeruma lista de cartões, determina quais cartões são visíveis.
No entanto, essa abordagem rouba as classes Carde as Playerclasses de uma possível função membro. Depois de fazer isso para outras coisas que a visibilidade de cartões, você é deixado com Carde Playerclasses que contêm dados puramente como toda a funcionalidade é implementada em outras classes, que são principalmente as classes sem dados, apenas métodos, como o Viewportacima.
Isso é claramente contra a idéia principal do POO.
Qual é o caminho correto? Como devo executar a tarefa de minimizar as interdependências de classe e minimizar o conhecimento e o acoplamento assumidos, mas sem acabar com um design estranho, onde todas as classes de baixo nível contêm apenas dados e as classes de alto nível contêm todos os métodos? Alguém tem alguma terceira solução ou perspectiva sobre o design de classe que evite todo o problema?
PS Aqui está outro exemplo:
Suponha que você tenha uma classe DocumentIdimutável, que tenha apenas um único BigDecimal idmembro e um getter para esse membro. Agora você precisa ter um método em algum lugar, que DocumentIdretorne Documentesse ID a partir de um banco de dados.
Você:
- Adicione
Document getDocument(SqlSession)método àDocumentIdclasse, introduzindo repentinamente conhecimento sobre sua persistência ("we're using a database and this query is used to retrieve document by id"), a API usada para acessar o DB e similares. Além disso, essa classe agora requer o arquivo JAR de persistência apenas para compilar. - Adicione outra classe com o método
Document getDocument(DocumentId id), deixando aDocumentIdclasse como morta, sem comportamento, como uma estrutura.