UML – Relacionamento entre Classes – Agregação

UML - Relacionamento de Agregação entre ClassesVocê já se perguntou o que é o relacionamento de Agregação entre Classes?

É algo que parece abstrato, mas é mais simples do que imaginamos.

Mas o uso inadequado da Agregação gera Alto Acoplamento e Baixa Coesão na estrutura de um software.

Este é o terceiro post sobre relacionamentos entre classes na UML – aqui você pode ver o primeiro sobre Dependência entre Classes, e aqui pode ver o segundo sobre Composição entre Classes.

Agregação na vida real

Como já citei em outros posts, sempre que pensamos em Orientação a Objetos devemos entender que o objetivo deste paradigma é refletir na estrutura do software a vida real do problema que o software busca resolver.

Vamos imaginar uma casa. Uma casa possui telhado e paredes, e não existe sem isso. Logo, uma casa é composta de telhado e paredes.

/* Num relacionamento de Composição podemos entender que classes que são compostas por outras precisam destas para “viver”, para “existir”. Por exemplo, a classe Coração compõe a classe Corpo Humano. Sem o coração o corpo humano não vive. */

UML - Relacionamento entre Classes - AgregaçãoMas uma casa existe, vive sem um espelho. Mas casas tem espelhos.

Neste contexto, o Espelho é uma Agregação, agrega-se à Casa.

Se a casa dependesse do Espelho para existir, então seria uma Composição.

E se a casa fosse feito de Espelhos, fosse esta sua matéria prima, então seria uma Herança.

São três forma de pensar um mesmo conceito, mas são semanticamente muito diferentes.

/* Num relacionamento de Agregação, podemos entender que classes que são agregadas por outras não precisam destas para “viver”, para “existir”. Por exemplo, a classe Unha agrega a classe Corpo Humano. Sem a unha o corpo humano vive sem grandes dificuldades. */

Agregação - eBook sobre Requisitos de Software

Agregação na UML e OOP

Agregação e Composição, que são relacionamentos de Associação, não são relacionamentos nativos da Orientação a Objetos. São utilizados na UML para representar modelos estruturais codificados no software.

Quando ocorre a implementação do código fonte, para a maioria das linguagens mais atuais este relacionamento é um tanto transparente, pois baseia-se apenas na utilização de um atributo na classe.

O diagrama de classe é que demonstra melhor a relação utilizada, bem como a multiplicidade aplicada.

uml-relacionamento-classes-composicao-csharp.png

Apenas lembrando, estas relações aplicam-se apenas a atributos de tipos complexos (ou tipo compostos), não aplicam-se a atributos de tipos primitivos.

Nesta imagem, Endereço e Contrato podem ser composições ou agregações, dependendo do que está modelado no diagrama relacionado à classe ClienteEntidade.

Exemplos

UML - Relacionamento entre Classes - Agregação

Nesta imagem temos a Classe Casa. Mas projetada da forma incorreta.

Cada classe deve ter apenas uma responsabilidade, e esta classe Casa possui responsabilidades que não são suas, pois possui coisas de Telhado, que é outra Entidade (conceitualmente falando), que deve possuir nela tudo referente a telhado.

E isso gera Alto Acoplamento, pois insere em Casa o que é de Telhado, além de ter também Baixa Coesão, pois mistura o conceito de Telhado com o conceito de Casa.

Vejamos abaixo a forma correta de modelar a classe Casa, com uma boa Separação de Responsabilidades, fazendo com que o modelo viabilize um software com Baixo Acoplamento e Alta Coesão.

UML - Relacionamento entre Classes - Agregação

Podemos ver que a classe Casa agora não possui mais coisas que são de responsabilidade de Telhado, pois isso está em uma classe separada. Lembrando que Casa precisa de Telhado para existir.

Mas Casa não precisa de Espelho para existir.

Logo, fizemos uma agregação da Classe Espelho para a classe Casa (Espelho agrega Casa).

Se excluirmos do modelo a classe Espelho, isso não vai deixar nossa Casa com problemas, pois espelho é um plus, não é algo essencial para a Casa existir.

Para melhorar o estudo, segue abaixo um vídeo, onde temos uma aula rápida explicando a aplicação da Agregação.

Concluindo

Softwares devem ser modelados antes de ser construídos, mesmo que apenas suas partes mais críticas. E na modelagem todo Analista de Sistemas deve ter como mantra a ideia de Fraco Acoplamento e Alta Coesão.

E quanto o assunto é Orientação a Objetos e UML, usar corretamente os relacionamentos entre classes na Modelagem é pré-requisito para isso virar realidade.

Se você gostou do conteúdo deste post, deixe seus comentários, para ajudar outras pessoas a encontrarem este material! :)

Grande abraço!

  • Giancarlo

    Olá, boa noite

    Parabéns pelo post, muito bom mesmo!

    Estou estudando muito sobre isso nos últimos dias, vamos a um exemplo

    Tenho uma entidade serviços e dentro dessa entidade a Entidade Cliente

    Na tela principal tenho uma grid para navegar nos serviços. Nessa lista quero mostrar o nr do serviço e o nome do cliente e o nome principal de outros objetos q agregam serviços

    Porque simplesmente não consigo navegar no objeto agregado para atribuir o que pesquisei no banco?

    Exemplo

    Select nrServico, nomeCliente from Servicos left join Clientes on servicos.idCliente=clientes.idCliente

    ListSevicos.add
    (
    new Servico
    {
    NrServico = reader[“NrServico”]
    ClientePrincipal.(não abre os atributos)
    }
    );

    Ou eu deveria criar uma entidade serviços prestados?

    Desculpe a escrita, estou no trem :)

    • Plínio Ventura

      Olá Giancarlo, tudo bem?

      Obrigado! Que bom que o conteúdo foi útil a você. Abaixo seguem meus comentários a respeito da sua dúvida.

      Você tem ClienteEntidade e ServicoEntidade. Não está claro a estrutura da classe ServicoEntidade, você informou apenas o número. Vou supor ainda que sua classe ClienteEntidade é algo tipo:

      public class ClienteEntidade()
      {
      private String nomeCliente { get; set; }
      private ServicoEntidade servico { get; set; }
      }

      E que sua classe ServicoEntidade é no mínimo assim:

      public class ServicoEntidade()
      {
      private Int32 nrServico { get; set; }
      }

      O seu Select parece ok. Imagino que você deve rodá-lo através de sua classe de dados (ClienteDados por exemplo). Vou supor que ServicoEntidade possui apenas um atributo, que é NrServico.

      Vou supor ainda que seu select rodou, você deu um “reader.Read();” no recordeset e veio os dados corretamente (nrServico e nomeCliente).

      Para pegar o recordset, iterá-lo e adicionar o conteúdo à sua lista, pode fazer assim:

      // 1º – Crie e instancie a lista de Clientes
      List listaCliente = new List();

      if (reader.HasRows)
      {
      while (reader.Read())
      {
      // 2º – No loop, você precisa criar uma instância de CADA CLASSE que agrega ClienteEntidade, no seu caso, ClienteEntidade e ServicoEntidade
      ClienteEntidade cliente = new Cliente();
      ServicoEntidade servico = new ServicoEntidade();

      //3º – E montar cada entidade que possui registro no reader, conforme abaixo
      cliente.nomeCliente = Convert.ToString(reader[0]);
      servico.nrServico = Convert.ToInt32(reader[1]);

      cliente.Servico = servico; //Talvez é aqui que você está com problema. Precisa primeiro instanciar servico, depois populá-lo, para depois atribuir a cliente

      //4º – E então, adicionar a ClienteEntidade à lista
      listaCliente.Add(cliente);
      }
      reader.NextResult();
      }

      Se o atributo NrServico da classe estiver com visibilidade PUBLICA, e você não ter ele como propriedade (get{} e set{}), teoricamente você tem que conseguir acessá-lo na sua classe ClienteEntidade. Verifique como ele está, se está private com get{} e set{}, ou público. Pode estar privado e você tentando acessá-lo diretamente, aí não conseguirá.

      Verifique ainda se tem atributos que deveria estar preechendo (não nullable [not null]), e isso pode não deixar compilar.

      Verifique também a visiblidade da classe ServicoEntidade, precisa ser pública para acessá-la de outra classe (supondo que não tenha nada entre elas, tipo um Façade ou Fabric).

      Se fizer mais ou menos como coloquei aqui, conseguirá navegar normalmente na lista. Veja se atendeu, e se não, coloque seus comentários.

      Abraço!

      • GIANCARLO FIOROTTI

        Olá, Bom dia

        Muitíssimo obrigado pela resposta!

        Eu tentei a solução acima mais ainda sem sucesso, fiz de uma outra forma, preenchendo a grid com um for na camada apresentação.

        No negócio apresentado, a classe serviços prestados é o objeto TODO que possui vários agregados Parte, no caso o cliente é um deles,

        Também possui composição que no caso são os documentos anexos e status do serviço prestado (objetos q não podem existir sem o objeto serviços prestados). Só pra você entender quão foi importante seu exemplo, tive uma ótima visão do que é agregação e composição

        • Plínio Ventura

          Bom dia, Giancarlo!

          Não precisa agradecer, que bom que o conteúdo lhe ajudou. Sobre sua dúvida pontual, realmente por aqui é custoso entender algum cenário mais elaborado, mas acho que foi válida nossa troca de ideias.

          Apenas uma sugestão, em relação ao “for” na camada de apresentação. Teoricamente, não há grande problema em fazê-lo, por se tratar de um recurso mais técnico, todavia, cuidado para não levar lógica de negócio para a camada de apresentação; isso contribui para misturar responsabilidades e gerar alto acoplamento.

          Mas se quiser falar mais, estamos à disposição.

          Ótima semana para você, e um grande abraço!

  • Fabio Aragao

    Por vezes achamos perolas como essa.. aprendi em 6 minutos o que não aprendi em algumas aulas na faculdade….

    • Plínio Ventura

      Obrigado, Fabio. Que bom que o conteúdo foi útil! Qualquer dúvida estamos à disposição, grande abraço!