Ainda não tem acesso? Estude com a gente! Matricule-se
Ainda não tem acesso? Estude com a gente! Matricule-se

Solid Acoplamento em classes compostas

Olá eu não sei se minha dúvida verdadeiramente relacionada ao SOLID, talvez seja de OO puro, é que ela surgiu no momento sobre acoplamento. Vamos lá: Eu normalmente penso em minhas classes (nem todas) como reflexão da modelagem do banco de dados (ainda mais em sistemas legados). Nesse sentido por exemplo pensando rapidamente em uma classe Animal onde todo Animal possui uma espécie e um Proprietário, nesse cenário eu teria 3 classes: Animal, Espécie e Proprietário.

Minha dúvida é: O melhor seria criar uma classe Animal que possui propriedades do tipo Especie e outra do tipo Proprietario, ou seja uma classe composta ? Isso não iria de encontro com o Acoplamento e Coesão de classe ? Mas por outro lado se eu criar uma classe Animal que ao invés de ser composta ter propriedades simples, por exempo CodigoProprietario e CodigoEspecie e precisar de uma lista de Animais para cada animal dessa lista eu precisaria fazer uma requisição ao banco de dados para carregar e a Especie e o Proprieatario ?

O que fazer ?

3 respostas

Oi Rodrigo, tudo bom?

Nesse caso, a semantica é quem deve mandar. Ou seja, aqui a gente aplica o verbo ser entre as classes e vê o que faz sentido. Se a frase fizer sentido a gente usa herança. Algo como:

Animal é Espécie? (não, animal é um reino)
Animal é Proprietário? (obviamente, não)
Proprietário é Animal? (sim, pela definição biologica pelo menos)

Então daqui sabemos que Proprietario herda de Animal.

Porém, a questão de espécies, como fica?

Pela definição biológica, Temos Reinos, Filos, Classes, Ordens, Familias, Generos e Especies.

Ou seja, o Reino animal, tem muitas classes, que tem muitas ordens, que tem muitas familias, generos e por fim tem muitas especies.

Isso significa que um Reino tem muitas Especies. Logo, nesse caso a semântica aponta para que a gente use composição ao invés de herança =)

Assim, a classe Especie seria um atributo dentro da classe Animal.

Nosso diagrama de classes ficaria algo como:

Animal extends Reino
    -> atributo especies (lista do tipo Especie)
Proprietario extends Animal    

Assim, mantemos a responsabilidade de Proprietário dentro da classe Proprietario, as de comportamentos e atributos comuns a animais em Animal e Especie de especies dentro de Especie.

Acho que aqui já temos uma boa representação do cenário. Porém, podemos ir além representando melhor a Especie. Pensando bem, uma Especie é também um animal. Logo, podemos fazer algo como:

Especie extends Animal

Isso faria com que a composição dentro da classe Animal se tornasse um relacionamento entre a classe Animal com a classe Especie (que herda de Animal também).

Perceba que todo mundo meio que acaba herdando de animal porque é um conceito biológico muito abstrato, todo ser vivo que não é uma planta basicamente é um animal, então podemos ir longe nesse exemplo.

O que importa aqui para garantir o principio de responsabilidade única, é olhar pro seu problema (regra de negocio) e aplicar essas regras semânticas do verbo ser e do verbo ter para não cair em uma herança errada e usar composição nas horas certas. Sempre pensando se o que você está atribuindo aquela classe realmente faz sentido. Por exemplo, você não colocaria um método voar() dentro da classe Proprietario porque não é responsabilidade de um proprietario voar. Faz sentido? =)

Abraço

Puxa que legal ! Faz total sentido. Acho que entendi, nessa sua explicação, aplicando nas classes animal, espécie e proprietário por exemplo em uma empresa de pet. Onde o proprietário possui um gato e um cachorro. E imaginando que na tabela de espécie do banco de dados eu tenha, por exemplo: canino, felino, aves Logo eu teria as classes:

Animal
EspecieCanina extends Animal
EspecieFelina extends Animal
EspecieAves extends Animal

Proprietário
possui um atributo animais que é uma lista de animais.

Seria isso ?

Nesse caso se eu quiser recuperar a persistência do banco de dados eu faria uma query selecionando todos os animais de um determinado proprietário e preencheria a lista de animais, surgiu a dúvida como sei qual a classe preciso criar para cada registro retornado do banco, sem usar ifs e hardcoding?

Obrigado

Oi Rodrigo, boa pergunta!

Na verdade, a gente não costuma gerenciar isso manualmente. Pra esse tipo de procedimento a galera costuma usar os ORMs (NHibernate, EntityFramework,etc).

Normalmente, os ORMs criam uma coluna a mais na tabela chamada discriminator. Que é basicamente uma string para identificar a classe especifica que a instância do banco representa.

Assim, na hora de puxar qualquer linha, por exemplo, pelo id, é só verificar o valor da coluna discriminator e instanciar o tipo certo direto =)