Engenharia de Software | Linguagem de modelagem unificada (UML) | Diagramas de Classes e seus elementos da UML
Conceitos do diagrama de classes
O diagrama de classes é considerado, por muitos, o principal diagrama da UML, sendo também o mais usado por aqueles que seguem essa linguagem na modelagem de seus sistemas. Existem vários níveis de diagrama de classes, que são usados em nível de domínio – conceitual – e de projeto. Abordaremos o diagrama de classes a partir da observação do mundo real para um determinado contexto; além disso, vamos construir o diagrama em nível de domínio, o chamado modelo conceitual de classes. Logo, não serão representadas, aqui, estruturas de projeto (interfaces, chaves, arquivos, campos, etc.).
O foco de nossa análise será o negócio.
Finalidades do diagrama de classes
O modelo conceitual de classes usa os elementos mais básicos do diagrama de classes, pois a finalidade é representar os objetos tal qual existem no mundo real, sem inserir aspectos de projeto ou de implementação no modelo.
O diagrama de classes descreve graficamente os tipos de objetos que interagem para realizar as funcionalidades previstas em um sistema, bem como os vários tipos de relacionamentos estáticos entre eles.
O diagrama de classes mostra ainda as propriedades e operações de uma classe, além de evidenciar as restrições referentes à forma como os objetos se relacionam.
A evolução do diagrama de classes
O diagrama de classes evolui à medida que a projeto avança.
Inicialmente, em sua primeira versão, na fase de análise, o diagrama apresenta as classes do negócio (também chamadas de entidades). Denomina-se diagrama de classes conceitual aquele compatível com as funcionalidades dos casos de uso; ou seja, ele mostra a modelagem em classes dos requisitos essenciais do sistema.
Na fase seguinte, de projeto, novas classes podem ser inseridas no diagrama de classes, que passa a se chamar diagrama de classes de projeto. Nesse diagrama são inseridas classes que mostram como será a arquitetura do sistema, a forma como surgem as classes de controle, de interface (ou fronteira) e auxiliares (como representação de persistência de dados etc.).
Principais classes
Conheça as principais entre essas classes:
Classe de fronteira (Boundary) ou interface – responsável pela interação com os atores. Exemplo: classe para representar um formulário, classe para representar a interface com outro equipamento (como um acionador de cancelas de entrada e saída de veículos).
Classes de controle – responsável pela coordenação da interação entre os objetos na realização de um caso de uso. Em princípio, cada caso de uso teria uma classe de controle.
Diagrama de classes de implementação
Até mesmo durante a implementação (codificação na linguagem), novas classes podem surgir como aquelas que requerem determinada característica da linguagem de programação ou certa forma de programar. É o diagrama de classes de implementação.
Na verdade, embora com diferentes nomenclaturas, o diagrama de classes é um só, que cresce e se altera a cada fase do ciclo de desenvolvimento. Algumas equipes de projeto podem optar por guardar as versões finais de cada diagrama, mas a última versão guarda todas as alterações feitas.
A classe
Uma classe é uma abstração da realidade, na qual representamos algo do mundo real. Se, por exemplo, em um contexto de sistema, identificarmos que desejamos armazenar dados de um determinado elemento, estamos diante de uma candidata à classe do sistema.
Na UML, uma classe é representada por um compartimento contendo três partes, conforme ilustrado na figura desta tela. Nome (1) é a denominação da classe; atributos (2) são os dados retidos da classe; e operações (3) são os procedimentos executados pela classe para prestar seu serviço ao sistema. Como um todo, são chamados de métodos.
A figura abaixo ilustra um exemplo de classe de nome cliente, contendo os atributos nome e matrícula e os métodos (operações) criar(), destruir() e incluir cliente().
Classe e objeto
A classe é o molde de um conjunto de objetos afins; ou seja, com as mesmas características (atributos e métodos). Um objeto é uma instância de uma classe.
Nesta tela, analise a imagem de um objeto específico pertencente à classe cliente. O objeto é como se fosse um elemento específico do conjunto (classe) cliente.
Na verdade, ao modelarmos um sistema, buscamos por classes, e não por objetos. Talvez, o nome mais apropriado para a técnica deveria ser orientação a classes, e não orientação a objetos.
Visão geral do diagrama de classes e seus elementos
A figura desta tela ilustra um diagrama conceitual de classes, contendo apenas classes de negócio (entidades) modeladas, bem como apresenta comentários dos principais elementos do diagrama de classes.
Um diagrama de classes possui os seguintes elementos básicos:
- Classes, com atributos e operações (métodos) de cada uma;
- Relacionamentos entre as classes;
- Multiplicidade dos relacionamentos;
- Visibilidade de atributos e métodos;
- Nome dos relacionamentos e papel nos relacionamentos;
- Navegabilidade nos relacionamentos;
- Notas e comentários.
Classes com seus atributos e operações
O conceito de ATRIBUTO remete ao conjunto de características (estado) dos objetos da classe.
O conceito de ATRIBUTO descreve uma propriedade estrutural da classe, um dado relevante que desejamos armazenar daquela classe. Segundo a UML, forma mínima de representar um atributo é: visibilidade Nome: tipo
Conforme figura abaixo, temos a classe DISCIPLINA e 4 atributos. Vejamos o atributo CODIGO:
- O sinal menos (-) antes do nome é a visibilidade, que explicaremos adiante.
- Código é o nome do atributo
- String é o tipo do atributo
Conceito de método
O conceito de MÉTODO remete ao conjunto de operações (comportamento) que a classe fornece.
A operação de uma classe é representada por um METODO, que é um procedimento ou função da classe. Segundo a UML a forma mínima de representar um método é: visibilidade Nome (Lista de parâmetros) : tipo
Conforme figura abaixo, temos a classe DISCIPLINA e 4 métodos. Vejamos o método RECUPERARCREDITOS(Cod:int):int
- O sinal mais (+) antes do nome é a visibilidade, que explicaremos adiante.
- RecuperarCreditos é o nome do método
- (Cod:int) é a lista de parâmetros, que no caso é composta de aenas 1 parâmetro; onde Cod é o nome do parâmetro e int o tipo de dado do parâmetro.
- Int e o tipo de dado que RECUPERACREDITOS retorna.
Observe que em 3 métodos o tipo de dados é VOID. Isso significa que esses métodos não retornam um tipo de dados, não sendo portanto uma função e sim um procedimento.
Associação entre classes
O relacionamento de associação é o mais simples e comum relacionamento entre classes. Ocorre entre uma, duas ou mais classes distintas, não correlatas e independentes. Ao final do relacionamento, as classes permanecem com suas vidas próprias.
A associação mais comum é entre duas classes, também chamada de associação binária, ilustrada no diagrama desta tela. Observe que o relacionamento de associação é denotado por uma linha sólida, que conecta as duas classes. Neste exemplo, as classes cliente e pedido se relacionam no momento em que o cliente faz um pedido à empresa.
Formas de associação entre classes
A associação pode ocorrer dentro de uma mesma classe, chamada de autoassociação ou associação unária. Nela, uma classe relaciona-se com ela própria, conforme ilustra a figura ao lado, onde o relacionamento é de prerrequisito. Pode ocorrer quando uma disciplina tem como prerrequisito outra disciplina da mesma classe.
São possíveis, também, relacionamentos com três ou mais classes. Todavia, é difícil encontrá-los no mundo real para modelagem. A figura ao lado exemplifica um relacionamento de associação entre três classes. No caso, o cliente contrata um projeto e um arquiteto.
A associação exclusiva é uma restrição em duas ou mais associações. Ela indica que objetos de uma determinada classe podem participar de, no máximo, uma das associações em determinado momento.
É representada por uma linha tracejada entre as associações, com a especificação {ou} denotando que o relacionamento é exclusivo a somente uma das duas classes.
O diagrama desta tela demonstra que um contrato somente pode ser firmado entre pessoas ou entre empresas, mas não pode haver contrato onde figure empresa e pessoa simultaneamente.
Multiplicidade nos relacionamentos
A multiplicidade é um conceito extremamente relevante nos relacionamentos. De uma forma bem simples, ela indica quantos objetos de cada classe podem estar envolvidos no relacionamento.
É um claro exemplo disso o relacionamento entre cliente e pedido, onde o cliente faz um pedido. Vamos analisar a multiplicidade de cada um dos dois lados do relacionamento:
Ao lado da classe cliente, temos que este pode realizar nenhum ou vários pedidos – observe que representamos essa multiplicidade ao lado de pedido, conforme ilustrado no diagrama.
Ao lado da classe pedido, está demonstrado que o pedido pertence a 1 e somente 1 pedido – essa multiplicidade está descrita ao lado de cliente, conforme demonstrado abaixo.
Aqui, enfim, a imagem completa, contendo as multiplicidades em ambos os lados do relacionamento.
A análise das multiplicidades entre relacionamentos de classes sempre deve acontecer dessa forma, ou seja, analise um lado de cada vez, de acordo com a ordem.
Possibilidades da multiplicidade
As possíveis multiplicidades são as seguintes:
A multiplicidade do diagrama de classes
Observe a multiplicidade do diagrama de classes no exemplo desta tela.
A classe equipefutebol tem de 11 a 22 estudantes – [11..22] ao lado da classe estudante;
A classe estudante pode participar de nenhuma até 8 disciplinas – [0..8] ao lado da classe disciplina:
Visibilidade de atributos e métodos
A visibilidade, no caso, diz respeito a quais atributos e métodos de uma classe podem ser utilizados por outra classe. A ideia consiste na classificação dos elementos de cada classe em privados ou públicos. O que for público poderá ser visualizado e usado por qualquer outra classe. O que for privado só poderá ser usado pela classe proprietária. Mas, ao sairmos da modelagem e passarmos à implementação, teremos que observar algumas particularidades relacionadas ao que é privado e ao que é público no tocante à visibilidade.
A UML aborda o tema sem entrar nessa condição e deixa a cargo da equipe de desenvolvimento esses aspectos de compatibilidade. Basicamente, a UML permite que se rotule todo atributo e método de uma classe com o indicador de visibilidade. Em todos os exemplos vistos até aqui, usamos a visibilidade pública (sinal de mais +) para os métodos, e visibilidade privada (sinal de menos -) para os atributos.
Confira no exemplo:
Diretrizes relevantes sobre visibilidade
A seguir, conheça as principais diretrizes sobre visibilidade:
- Um dos princípios básicos da orientação a objetos, o encapsulamento, diz que os atributos de uma classe não devem ser usados por outras classes, e, sim, apenas por métodos da própria classe. Portanto, os atributos devem ser classificados com a visibilidade do tipo privada (-);
- Uma classe deve prestar serviço às demais através de seus métodos. Assim sendo, pelo menos um dos métodos da classe deve ter visibilidade pública para que as demais classes possam utilizá-lo;
- Num relacionamento de generalização/ especialização, todos os atributos e métodos desejáveis para serem herdados pela classe especializada (subclasse) devem ter a visibilidade protegida na classe geral (superclasse).
Outros relacionamentos entre classes
Os relacionamentos representam os mais relevantes elementos de um diagrama de classes. Estudaremos os relacionamentos mais usados na modelagem de classes. Veja que, além das associações incluídas na lista, são possíveis os seguintes relacionamentos:
- Classe de associação
- Generalização / Especialização (herança)
- Agregação
- Composição
- Dependência
Classe de associação
No exemplo desta tela ilustra o relacionamento entre classes chamado de classe de associação. É uma classe que surge do relacionamento de associação entre outras duas classes. Imagine que um leitor (classe) de uma biblioteca solicita empréstimo do exemplar de livro (classe). Nesse momento, surge a necessidade de armazenar alguns atributos, como: datas de empréstimo e de devolução, além de métodos para registrar o empréstimo e a devolução e para tratar a multa em caso de atraso na devolução. Tais atributos e métodos não podem ser associados à classe leitor, nem tampouco à classe exemplar de livro. Não seria adequado incluir tais atributos e métodos em nenhuma dessas classes, pois não dizem respeito a elas. Surge, então, uma nova classe, denominada empréstimo, como consequência da associação entre leitor e exemplar de livro, que deverá armazenar todos os atributos e métodos derivados dessa associação.
O relacionamento do tipo classe de associação é representado através de uma reta pontilhada a partir de uma associação entre duas classes, conforme a figura desta tela.
Generalização/especialização
A generalização/especialização é o relacionamento entre classes que implementa o conceito de herança, com reaproveitamento de código, preconizado pela orientação a objetos. Uma classe mais geral relaciona-se com outra mais específica (herdada). A classe mais específica herda todas as características (atributos e métodos) permitidas da classe mais geral. A classe mais geral também é chamada de superclasse, e a classe mais específica chama-se subclasse.
Este exemplo ilustra o relacionamento de generalização/especialização em um exemplo típico, envolvendo clientes (pessoas físicas e jurídicas), que têm diferenças, mas, também, semelhanças, que podem ser agrupadas na classe mais geral, cliente (a superclasse), e as diferenças ficam nas subclasses pessoa física e pessoa jurídica.
O relacionamento de generalização/especialização é representado por uma reta com uma seta sem preenchimento na ponta, apontando para a classe mais geral. Deve-se ler que: a pessoa física é um cliente; a pessoa jurídica é um cliente.
O relacionamento de generalização/especialização contém algumas especificidades, chamadas restrições, que acrescentam informações mais precisas sobre como a generalização deve ser usada e estendida no futuro.
Generalização/especialização
Generalização completa e incompleta
Uma restrição que indica que a generalização é completa significa que todas as subclasses (especializações) já foram especificadas, e não existe mais possibilidade de outra generalização no futuro. A incompleta é o contrário e é a padrão da UML. O exemplo desta tela ilustra o uso dessa restrição completa, onde uma pessoa é homem ou mulher, não havendo novas subclasses possíveis para a superclasse pessoa.
HERANÇA
A figura desta tela mostra o princípio da herança chamado transitividade:
A classe Cl2 herda o atributo Cl1 (visibilidade protegida);
A classe Cl3 herda o atributo M2 de Cl2;
A classe Cl3 herda o atributo M1 de Cl1 pelo princípio da transitividade.
Diferenciando agregação e composição
Uma das maiores fontes de confusão na modelagem de classes é o uso dos relacionamentos de agregação e composição. Esses relacionamentos são do tipo “todo-parte”. Existe uma classe que denota um todo, e outra(s) que denota(m) a(s) parte(s). A grande dificuldade está em diferenciar agregação de composição.
A composição é um relacionamento mais forte, onde podemos prever as seguintes características:
- Embora uma classe possa ser um componente de muitas outras classes, toda instância deve ser componente de apenas um proprietário, o que significa dizer que teremos a cardinalidade 1 do lado do objeto todo (proprietário). Em outras palavras, os objetos parte somente podem pertencer a um único objeto todo;
- Se o todo for excluído, todas as partes também devem ser; ou seja, quando o todo “morre”, todas as partes também “morrem”. A vida do todo e das partes são coincidentes.
Quando num relacionamento todo-parte as duas características (ao lado) não forem identificadas, estaremos diante de uma agregação; ou seja, a constatação de que o relacionamento é uma agregação deriva da análise das duas propriedades dos tópicos ao lado e da conclusão de que ele não é uma composição.
Composição
A representação da composição é feita através de um losango (que muitos chamam de diamante) preenchido de preto – como pode ser observado na ilustração. Esse losango deve ser posicionado ao lado do objeto todo.
Por que o relacionamento entre pedido e itens pedido é uma composição?
Analisando o relacionamento ilustrado na figura desta tela sob a luz das duas características vistas, temos:
- O objeto parte (itens pedido) não pode pertencer a mais de um todo, pois aquele item é daquele pedido e não poderá estar em outro;
- Quando um pedido deixa de existir, não faz sentido os seus itens permanecerem ativos, “vivos”; logo, quando o pedido (todo) “morre”, os itens pedido (parte) também “morrem”.
Conclusão: como as duas características foram verificadas e encontradas, podemos afirmar que o relacionamento entre pedido e itens pedido é uma composição.
Agregação
A representação da agregação também é feita através de um losango (que muitos chamam de diamante); porém, sem preenchimento, ao lado do objeto todo.
Por que o relacionamento entre prova e questões é uma agregação?
Analisando o relacionamento, ilustrado na figura desta tela sob a luz das duas características vistas, temos:
- O objeto parte (questões) pode pertencer a mais de 1 todo, uma vez que uma questão pode ser parte integrante de mais de uma (várias) prova(s);
- Quando uma prova deixa de existir, as questões nela contidas podem (e devem) continuar existindo para que possam ser usadas em outras provas; logo, a vida das partes não é coincidente com a vida do todo.
Conclusão: já que nenhuma das propriedades foi verificada como verdadeira, podemos concluir que o relacionamento entre prova e questões não se trata de composição. E como é um relacionamento todo-parte, concluímos tratar-se de uma agregação.
Embora as duas características ajudem muito a elucidar qual dos relacionamentos (composição ou agregação) é o mais apropriado, sempre analise o contexto a fim de entender como se relacionam todo e parte.
A composição é um relacionamento que diz muita coisa a quem implementará as classes, quanto à linguagem de programação. Essa forma de relacionamento orienta que a criação e destruição das partes estão condicionadas à vida do todo. Já a agregação não apresenta essa particularidade. Uma agregação poderá, se desejado, ser substituída por uma associação simples, por não ter grandes valores semânticos e não explicitar que se trata de uma relação todo-parte.
Dependência
A dependência entre duas classes existe se mudanças na definição de uma classe demandam alterações na definição da outra classe. As dependências podem ser evidenciadas de várias formas, como, por exemplo:
- Uma classe tem outra como parte de seus dados;
- Uma classe menciona outra como parâmetro de uma chamada de método.
Se a interface da classe dominante muda, as mensagens enviadas podem não ser mais válidas, demandando alterações na classe dependente.
Sabemos o quanto esse tipo de alteração provoca problemas endêmicos em sistemas, acarretando o chamado efeito em cascata; ou seja, uma pequena alteração do código leva erros e problemas a outras partes.
Em modelagem UML, veremos muitas dependências, mas você deverá ser seletivo e modelar dependências apenas quando forem relevantes para o contexto específico de sua aplicação. Um dos usos mais comuns da dependência é na modelagem de um relacionamento transitório, da mesma maneira quando um objeto é passado para outro como parâmetro.
O exemplo desta tela ilustra um relacionamento de dependência entre as classes estudante e disciplina. A dependência é representada por uma seta pontilhada, que sai da classe dependente; ou seja, nesse relacionamento, disciplina depende de estudante. Observe que o método incluir da classe disciplina usa como parâmetro o objeto aluno, que é da classe estudante. Isso significa que qualquer mudança na interface (assinatura) de estudante poderá afetar a classe disciplina.
Nome e papel de um relacionamento
Conforme ilustra o exemplo desta tela, pode ser dado um nome ao relacionamento; no caso, faz. O nome mais o sentido indicado pela seta indicam a leitura, que, no caso, é: cliente faz pedido.
O papel em um relacionamento refere-se ao nome dado para o papel que cada classe representa no relacionamento. Semanticamente, é útil para entendimento do diagrama. Cada classe pode ter o nome de seu papel descrito no relacionamento, conforme ilustra a figura abaixo. Seu uso é opcional e, caso seja necessário, pode-se especificar o papel de apenas uma das classes no relacionamento.
Observe que, na figura que exemplifica o conteúdo:
- Faz é o nome do relacionamento, com a seta apontada para pedido a indicar que a leitura é nesta direção: cliente faz pedido;
- Possui é o nome do relacionamento entre pedido e itens pedido, com a seta apontada para itens pedido, indicando que a leitura é nesta direção: pedido possui itens pedido;
- “Faz pedido” é o papel que cliente tem no relacionamento entre cliente e pedido;
- “Cada item do pedido” é o papel que itens pedido tem no relacionamento entre pedido e itens pedido.
Observe o diagrama de classes (já visto anteriormente) apresentado nesta tela. Perceba que a classe estudante pode representar dois papéis distintos: aluno de uma disciplina e jogador de uma equipe de futebol. Logo, neste caso, o papel é bastante útil na interpretação do relacionamento.
Navegabilidade nos relacionamentos de Associação
A navegabilidade mostra a direção da navegação; por exemplo, uma associação é dita navegável da classe C1 para a classe C2 caso, a partir de um objeto de C1, obtenha-se diretamente os objetos relacionados da classe C2. Denota-se, a partir do diagrama de classes, a capacidade de um objeto mandar mensagens a objetos de outra classe.
Observe o diagrama de classes no exemplo desta tela, onde está sendo representada a navegabilidade da associação entre as classes cliente e endereços. O principal aspecto da simbologia é a seta direcionada à classe endereços.
A interpretação é a seguinte:
- O cliente sabe quais são seus endereços;
- Mas o endereço não sabe a quais clientes pertence;
- A classe cliente poderá enviar mensagens à classe endereços, mas não o contrário;
- Essa é uma notação semântica que ajuda muito na implementação.
Notas e comentários no diagrama de classes e UML
Notas são comentários podem ser usados em qualquer diagrama. Elas são diferenciadas entre isoladas ou vinculadas (por linha tracejada) a um dos elementos do diagrama. A figura abaixo ilustra as duas possibilidades: notas associadas a um elemento (no caso, à classe endereços) e nota associada ao diagrama (de uma forma geral).
Atividade proposta
Imagine a seguinte cena: uma clínica oftalmológica precisa de um sistema de agendamento de consultas e exames.
Um paciente contata a clínica, por telefone ou pessoalmente, e solicita a marcação de uma consulta com seu médico de preferência, informando data e hora desejadas;
A atendente verifica na agenda do médico a disponibilidade mais próxima de data e hora, e marca a consulta;
Na data e hora agendadas, o paciente realiza sua consulta, onde o médico solicitou exames e prescreveu medicamentos;
Após a consulta, o paciente solicita à atendente a marcação de seus exames, informando data e hora pretendidas. A atendente verifica disponibilidade próxima à solicitada e agenda o exame para o paciente;
A qualquer momento, o paciente pode solicitar o cancelamento, não apenas da consulta, mas, também, do exame.
A seguir uma dos possíveis diagramas de classes, com base na solução dada no diagrama de casos de uso da aula 2:
Responda às questões a seguir, que constituem um passo a passo para obtenção do diagrama de classes, baseado no diagrama de casos de uso:
1) Precisamos reter no sistema dados de algum ator? Ou seja, algum ator é candidato à classe?
2) Quais casos de uso dão origem a classes?
3) Quais casos de uso dão origem a métodos de uma classe?
4) Como relacionar as classes envolvidas?
Depois, desenhe o diagrama de classes (derivado do diagrama de casos de uso).
Chave de resposta
1) Precisamos reter no sistema dados de algum ator? Ou seja, algum ator é candidato a classe?
a. Sim, paciente e médico.
2) Quais casos de uso dão origem a classes?
a. Consultar paciente -> classe consulta;
b. Agendar exame -> classe exame;
c. Consultar paciente -> classe prescrição, já que, na consulta, o médico prescreve medicamentos.
3) Quais casos de uso dão origem a métodos de uma classe?
a. Classe consulta: agendar consulta, cancelar consulta, consultar paciente;
b. Classe exame: agendar exame, cancelar exame.
4) Como relacionar as classes envolvidas?
Para saber mais sobre metodologias de desenvolvimento ágil, acesse e leia os conteúdos dos sites indicados:
Organização UML; http://www.uml.org/
MINDOMO. https://www.mindomo.com/pt/mindmap/versoes-uml-164c4e92e9c8458ca29cd8e569b1511f
REFERENCIAS
BEZERRA, Eduardo. Princípios de análise e projeto de sistemas com UML. 2. ed. Rio de Janeiro: Campus, 2006.
BOOCH, G.; JACOBSON, I.; RUMBAUGH, J. UML: guia do usuário. 2. ed. Rio de Janeiro: Campus, 2006.
FOWLER, M. UML essencial: um breve guia para a linguagem-padrão de modelagem de objetos. 3. ed. Porto Alegre: Artmed, 2005.
LARMAN, C. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados a objetos e ao desenvolvimento interativo. 3. ed. Porto Alegre: Bookman, 2008.
PRESSMAN, R. S. Engenharia de software: uma abordagem profissional. 7. ed. São Paulo: McGraw Hill Brasil – Grupo A, 2011.
SOMMERVILLE, I. Engenharia de Software. 8. ed. São Paulo: Pearson, 2007.
Engenharia de Software | Linguagem de modelagem unificada (UML) | Diagramas de Classes e seus elementos da UML