Dependência entre Classes

Você fez uma alteração em algum sistema, e na hora de compilar viu que a IDE (Visual Studio, Eclipse) gerou um monte de erros que não existiam antes? E quando foi analisar os erros, percebeu que houve quebra em vários pontos do sistema, devido a incompatibilidade entre classes?

Dependência entre Classes – isso precisa ser avaliado.

Dependência entre Classes - Erro de Compilação - Visual Studio

Muitas vezes, uma simples exclusão de um atributo de uma classe pode gerar dezenas de quebras no sistema, inviabilizando a compilação, e demandando refatoração.

A causa disso é que há relacionamento de dependência entre as classes contidas na estrutura do sistema.

Neste contexto – devido ao acoplamento entre estas classes – dependendo da alteração realizada em uma classe, pode haver efeito colateral em várias outras que dependem dela.

Dependência entre Classes

Quando falamos de Orientação a Objetos, estamos falando de trazer o mundo real para dentro do projeto de software, onde devemos tentar ao máximo espelhar na estrutura do sistema (seus domínios, módulos, camadas, classes, métodos) o cenário real do problema que o software está resolvendo.

/* A OOP ou POO – Programação Orientada a Objetos – foi pensada, dentre outros motivos, para viabilizar o desenvolvimento de software com uma visão mais próxima da vida real, da realidade do problema, quando na implementação da solução. Por exemplo, ao invés de ter uma lista de classes, com nomes como cls123, cls456, cls789, todas elas no mesmo nível hierárquico na estrutura do sistema, a POO nos orienta a pensar no cenário do cliente, e modelar as classes, por exemplo, conforme a realidade do negócio. Se temos três classes, onde uma representa o cliente, outra um fornecedor, e outra um vendedor, seguindo a POO poderíamos ter uma outra classe chamada Pessoa, e Cliente, Fornecedor e Vendedor herdarem dela, e conceitualmente teríamos classes com nomes como, PessoaEntidade, ClienteEntidade, FornecedorEntidade, VendedorEntidade, e escopos também próximos da vida real, do negócio. */

E na vida real, a dependência acontece sempre.

Dependência entre Classes - eBook sobre Requisitos de Software

Vamos imaginar uma Casa (que seria nossa classe). Para uma Casa existir, ela depende de uma Rua, e depende também de um Lote. Depende porque sem a Rua ou sem o Lote a Casa não consegue ser uma Casa. E por depender do Lote ou da Rua, qualquer alteração na estrutura do Lote ou da Rua pode gerar efeito colateral na casa.

Por exemplo, se houver uma mudança no tamanho útil do Lote, imposta pela Prefeitura, que visa reduzir o tamanho da área construída dentro dela, isso vai gerar impacto na casa, que terá que ter uma demolição parcial para adequar-se à nova legislação imposta. Ainda, se houver uma obra na rede de esgoto da rua, que paralise a rede de esgoto da rua por 48 horas, isso vai gerar efeito colateral na casa, que não poderá ser habitada por 48 horas, pois uma casa sem sistema de esgoto não funciona.

Esse tipo de relacionamento é muito comum entre as partes de um sistema. As partes do todo geralmente funcionam juntas.

Cuidados ao utilizar Dependência

Mas toda facilidade tem seu custo. Utilizar dependências favorece o alto acoplamento na estrutura do sistema, e isso não é bom. Mas é uma facilidade pois diminui a complexidade na modelagem do sistema. Tentar não usar dependência na maioria das vezes, torna a implementação mais complexa, o que demanda mais tempo para modelar e implementar a solução, e dificulta a manutenibilidade do software (considerando o perfil médio de Analista de Sistemas).

Então, é importantíssimo utilizar com bom senso as dependências, procurando sempre isolar as classes quando possível, focando sempre no desacoplamento.

Um conceito fundamental de entender, para quem quer implementar soluções desacopladas é a Injeção de Dependência. Recomendo que, quem puder, estude sobre o assunto. E ainda, alguns Padrões de Projeto (Design Patterns), tanto Criacionais como Estruturais,  que são pertinentes para ajudar no desacoplamento, por exemplo: Façade, Simple Factory, Factory e Abstract Factory.

Relacionamento de Dependência no Diagrama de Classes

Dependência talvez seja o relacionamento mais comum entre as classes de um sistema. Em função do uso de diagramas não ser algo onipresente nas empresas que produzem software, e também por muitas dependências não serem de conhecimento do analista (nem todo profissional sabe o que “vem junto” com um usign ou um import por exemplo) talvez isso não seja percebido.

Em termos práticos, a existência de dependência entre classes significa que para uma classe ser compilada e/ou executada a outra classe precisa estar “linkada” a ela (às vezes a dependência ocorre apenas em tempo de execução, quando há o uso de injeção de dependência, factories, reflexão etc.).

A seguir temos um pequeno diagrama, com a explicação dos detalhes logo a seguir:

Dependência entre Classes - Diagrama de Classes

No diagrama acima temos três classes, e uma relação de dependência da classe “ClienteNegocio” para as classes “ClienteEntidade” e “ClienteFiltro”.

Porque ClienteNegocio depende de ClienteEntidade?

Em todos os métodos da classe podemos perceber que parâmetros ou retorno são do tipo ClienteEntidade. Então a classe de negócio não pode nem ser compilada sem levar junto ClienteEntidade, por razões de referência. Para existir, ClienteNegocio depende de ClienteEntidade.

Porque ClienteNegocio depende de ClienteFiltro?

No método BuscarPorFiltro(…) o tipo do parâmetro utilizado é ClienteFiltro. Como no caso anterior, não é possível nem compilar sem a referência à classe citada. Para existir, ClienteNegocio depende de ClienteFiltro.

Porque ClienteEntidade e ClienteFiltro não dependem de ClienteNegocio?

Como pode-se ver no diagrama, a direção do relacionamento é de ClienteNegocio para as outras duas classes. Isso porque ClienteNegocio depende delas, mas elas não dependem de ClienteNegocio, vivem sem ela. No contexto apresentado são classes POCO (no C#, POJO no Java), não dependem de nenhuma classe específica salvo as do próprio framework utilizado.

Como ver as dependências em sistemas que não possuem diagramas de classe

Quando o sistema possui artefatos de modelagem de sua estrutura e arquitetura, como diagramas de classe, basta consultar estas especificações para verificar como foram projetados os relacionamentos entre as classes do sistema.

/* Apenas um detalhe: infelizmente é pouco comum que empresas que produzam diagramas nos projetos de software não deem manutenção adequada nestes artefatos, gerando muita defasagem de informação (o software evolui mas a documentação “fica no passado”). Se isso for plausível no projeto em que está, não confie cegamente nas especificações, sempre verifique no sistema se o que está especificado está igual ao que está implementando no código fonte. */

Quando não existem diagramas de classe, essa verificação tem que ser feita diretamente na IDE, na ferramenta utilizada para desenvolvimento do sistema.

As IDEs mais antigas não possuem recurso para isso, mas IDEs mais modernas como o Visual Studio ou Eclipse possuem. Estes recursos são chamados de “Find References” ou “Call Hierarchy”. Abaixo dois exemplos, o primeiro do Eclipse e o segundo do Visual Studio, com um dos recursos citados.

Dependência entre Classes - Eclipse - Call Hierarchy - Java

Dependência entre Classes - Visual Studio - Call Hierarchy - Csharp

Grande abraço a todos!

Dependência entre Classes

  • Josias

    Interessante sua forma de explicar. Achava que toda relação entre classes era dependência, mas vejo que somente em poucos casos. Obrigado.

    • Plínio Ventura

      Oi Josias,

      Sem dúvida, ha muitas sutilezas na relação entre classes. Se ignorarmos os outros tipos de relacionamento, poderíamos sim considerar todos os tipos de relação entre classes como dependência – pois se uma classe relaciona-se à outra, somente funcionarão se estiverem juntas. Mas o objetivo de qualificar o relacionamento como agregação, composição, generalização (herança) e associação é deixar mais claro o objetivo/significado da relação entre as classes, fortalecendo assim a semântica do modelo projetado.

  • Pingback: Relacionamento entre Classes - Composição - Até o Momento()

  • Pingback: UML - Relacionamento entre Classes - Agregação - Até o Momento()