Diagrama
de Classes
Identificação de
Classes
As classes são a estrutura
de dados que darão ao programador a noção do domínio do problema.
O modelo de classes tem os
dados e o comportamento destes.
Uma classe é uma abstração
de um conjunto de coisas que possuem características e operações em comum. Ela surge da
união de vários objetos que possuem coisas em comum.
Os atributos de uma classe
correspondem à descrição dos dados armazenados pelos objetos. A cada atributo
de uma classe está associado um conjunto de valores que esse atributo pode
assumir. Cada instância de classe assume valores diferentes para cada atributo.
As operações correspondem
à descrição das ações que os objetos de uma classe sabem realizar. Objetos de
uma classe compartilham as mesmas operações.
Conceitos que ajudam na identificação e
definição de classes e métodos:
- Modelar
como classes as entidades que ocorrem naturalmente no domínio do problema;
- Projetar
métodos com um único objetivo;
- Projetar
um novo método quando se defrontar com a alternativa de ampliar um já
existente;
- Evitar
métodos extensos;
- Armazenar
como variáveis de instância os dados que são necessários a mais de um
método ou a uma subclasse;
- Projetar
para uma biblioteca de classe, não para si próprio ou para sua aplicação.
Uma nova classe deve ser criada quando:
- A
nova classe representar uma abstração significativa para o domínio do
problema;
- Os
serviços que ela proporcionar forem provavelmente usados por várias outras
classes;
- O
seu comportamento for inerentemente complexo;
- A
classe ou método fizer pouco uso das representações dos seus operandos;
- Se
representada como um método de uma outra classe, poucos usuários desta
classe a solicitariam.
Regras para elaborar classes abstratas:
- Identificar
mensagens e métodos comuns e migrá-los para uma super classe. Isto pode
criar a necessidade de quebrar métodos e dividi-los entre superclasses e
subclasses;
- Eliminar
os métodos de uma superclasse que são freqüentemente sobrescritos em vez
de herdados por suas subclasses. Isto tornará a superclasse mais abstrata
e conseqüentemente mais útil;
- Acessar
todas as variáveis somente pelo envio de mensagens. As classes ficarão
mais abstratas quando dependerem menos das suas representações de dados;
- Trabalhar
subclasses para serem especializadas. Uma subclasse será especializada se
herdar todos os métodos da superclasse e acrescentar novos a si própria.
Uma subclasse deveria sempre representar um superconjunto do comportamento
de seus pais.
Classes Iniciais
A identificação das classes
tem como objetivo saber quais objetos irão compor o sistema.
O modelador analisa cada
Use Case para identificar as classes candidatas a desempenhar
responsabilidades.
O nome do ator deve ser removido
da lista de classes candidatas se não for necessário que o sistema mantenha
informações sobre o mesmo.
Uma única classe não deve
ser sobrecarregada com responsabilidades demais. Não se deve concentrar a
inteligência do sistema em uma única classe.
Responsabilidades
conceitualmente relacionadas devem ser mantidas em uma única classe. Ex.:
Cliente
Deve-se evitar redundância
de responsabilidades.
Após construir o modelo de
Use Case e o de classes, verificar a consistência entre os dois modelos.
Os modelos de Use Case e de
Classe são estáticos, o aspecto dinâmico do sistema é representado pelo modelo
de interações e pelo modelo de estados.
Há dois métodos principais
para identificar classes: dirigido a dados e dirigido a responsabilidades.
No método dirigido a dados,
a ênfase está na identificação da estrutura dos conceitos relevantes para um
domínio de negócio. Resulta em um modelo conceitual do sistema.
No método dirigido a
responsabilidades, a ênfase está na identificação de classes a partir de seus
comportamentos relevantes para o sistema. Enfatiza o encapsulamento da
estrutura e do comportamento dos objetos.
No diagrama de classes,
define-se três recursos de notação: nome da associação, direção de leitura e
papel. Devem ser usados quando o significado
de uma associação não for muito óbvio.
Atributos
Um atributo é um valor de
dado guardado pelos objetos de uma classe. Cada atributo possui um valor para
cada instância de objeto. Diferentes instâncias de objetos podem ter valores
iguais ou diferentes para um dado atributo.
Com relação aos atributos
a sintaxe proposta é:
Visibilidade
NomeAtributo:TipoDoAtributo = ValorDefault {propriedade}
·
Visibilidade
Trata-se
de uma marcação que pode ser realizada pelos símbolos (+, #, -).
(+)
Visibilidade pública – é acessível por todas as classes (valor default)
(#)
Visibilidade protegida – pode ser vista pela classe e pelo pacote no qual a
classe é definida
(-)
Visibilidade privada – somente acessível pela própria classe.
·
NomeAtributo
Seqüência
de caracteres que devem formar um nome auto-explicativo.
·
TipoDoAtributo
Expressa
o tipo do conteúdo que se pretende armazenar para o atributo. Ligada à
linguagem de programação.
·
ValorDefault
Refere-se
ao conteúdo inicial do atributo, de acordo com seu tipo.
·
{propriedade}
Elemento
opcional, que complementa informações a respeito do atributo.
Atributo Derivado
Quando o valor do atributo
pode ser obtido a partir do valor de outro(s) atributo(s). É representado com
uma barra inclinada à esquerda.
Atributo Estático
Pode haver atributos que
tenham escopo de classe, ou seja, que armazenam valor comum a todos os objetos
da classe. Sintaxe na UML: sublinhado.
Usado na implementação de regras de negócio. Ex.: QuantidadeMaximaAlunos em uma
classe CURSO.
Com relação aos métodos, a
sintaxe geral sugerida é:
Visibilidade
NomeDoMétodo (Parâmetro) : TipoDeRetorno {propriedade}
·
Visibilidade
Trata-se
de uma marcação que pode ser realizada pelos símbolos (+, #, -).
(+)
Visibilidade pública – é acessível por todas as classes
(#)
Visibilidade protegida – pode ser vista pela classe e pelo pacote no qual a
classe é definida
(-)
Visibilidade privada – somente acessível pela própria classe.
·
NomeDoAtributo
Representa
a operação que será processada.
·
Parâmetro
Trata-se
de uma lista de valores devidamente separados por vírgula.
O
elemento direção serve para definir se o parâmetro pode ou não ser modificado
pela operação. Através desse elemento, o modelador pode definir se o parâmetro
é de entrada, saída ou ambos.
Direção
|
Significado
|
in
|
Parâmetro de entrada:
não pode ser modificado pela operação. Serve somente como informação para o
objeto receptor.
|
out
|
Parâmetro de saída: pode
ser modificado pela operação para fornecer alguma informação ao objeto
remetente.
|
inout
|
Parâmetro de entrada que
pode ser modificado.
|
·
TipoDeRetorno
Expressa
o tipo do conteúdo que se pretende obter de retorno do método. Ligada à
linguagem de programação.
·
{propriedade}
Elemento
opcional, que complementa informações a respeito do método. Podem ser uma ou
mais das seguintes: isQuery, sequential, guarded, concurrent.
IsQuery
indica que a execução de tal operação não modificará o estado do objeto. Não
modifica atributos nem associações do objeto.
As
demais propriedades são utilizadas em sistemas multi threaded.
Todas as operações que são
declaradas nas mensagens de um objeto a outro em um diagrama de interação devem
ter visibilidade pública.
As operações possuem um
escopo. Uma operação que tem escopo de classe processa atributos estáticos.
Classe Virtual – Interface
Há um tipo especial de
classe a qual não pode ser instanciada, ou seja, não se conseguirá gerar
objetos diretamente dela, o que a torna uma classe virtual/abstrata, servindo
apenas para especificar as operações externamente visíveis para uma classe. Uma
interface descreve padrões legais de interação entre dois objetos. A interface
funciona como uma classe modelo, que outras classes poderão fazer uso,
implementando as funcionalidades descritas. Estereótipo <<type>>.
Define uma classe virtual, que não possui atributos e cujos métodos serão
implementados em outras instâncias.
Relações entre classes
Para que classes executem
suas tarefas é necessária a interação entre elas. As classes podem apresentar alguns tipos de
relações: herança, dependência, associação, agregação/composição e classe
associativa
Ligações e Associações
Uma ligação é uma conexão
física ou conceitual entre instâncias de objetos.
Uma associação descreve um
grupo de ligações com estrutura e semântica comuns. Todas as ligações de uma
associação interligam objetos da mesma classe. Ex.: Pessoa Trabalha-para
Empresa.
Ex. : Diagrama de classes: País Tem_capital Cidade
Diagrama de instâncias: Canadá Tem_capital Ottawa
As associações podem ser
unárias, binárias, ternárias ou de ordem mais elevada. Não é aconselhável
utilizar associações de ordem elevada.
O mais usual é a
associação binária que é representado por uma linha ligando as classes.
Uma associação ternária é
uma unidade atômica e não pode ser subdividida em associações binárias sem
perder informações. Ex.: Pessoas que são programadoras usam linguagens de
programação em projetos.
Uma associação unária é
também conhecida como associação recursiva, pelo fato de ser um relacionamento
entre objetos da mesma classe.
Navegabilidade de
Associações
Devem ser definidas para
todas as associações. Na maioria das vezes ela é bidimensional. Caso não haja a
necessidade, recomenda-se transforma-la em unidirecional, para facilitar a
implementação.
Pode-se usar o diagrama de
interações para definir o sentido da navegabilidade. Dados dois objetos
associados, A e B, se há pelo menos uma mensagem de A para B em algum diagrama
de interação, então a associação deve ser navegável de A para B, e vice-versa.
Agregação
É a relação “parte-todo”
ou “parte-de-um” no qual os objetos que representam os componentes de alguma
coisa são associados a um objeto que representa a estrutura inteira. Usado para
mostrar que um tipo de objeto é composto de outro objeto.
A agregação por valor, ou
composição, (losango cheio) indica que o tempo de vida das partes são
dependentes do tempo de vida do todo. Ex.: Pedido e Itens Pedido A agregação
por referência (losango sem
preenchimento), o tempo de vida das partes não são mutuamente dependentes do
tempo de vida do todo. Ex.: Curso, disciplinas e salas.
Na agregação, os objetos
que fazem parte do todo são criados e destruídos independentemente deste
último. Além disso, um objeto-parte pode ser utilizado para compor diversos
objetos-todo. A destruição de um desses objetos-todo não implica na destruição
do objeto-parte.
Na composição, os objetos
parte pertencem a um único todo. Além
disso, objetos-parte são sempre criados e destruídos pelo objeto-todo. Se o
todo deixa de existir, o mesmo acontece com suas partes.
Tanto na agregação quanto
na composição, o todo tem prioridade para criar suas partes. Portanto, é mais
adequado que o objeto todo crie suas partes quando requisitado por outros
objetos.
Classes Associativas
Este tipo de classe
normalmente aparece quando duas ou mais classes estão associadas, e é
necessário manter informações sobre a associação. Ligadas a associações de
multiplicidade muitos para muitos.
Diferenciam-se de
associações ternárias pois estas são utilizadas quando é preciso associar
objetos de três classes distintas.
Dependência
Um relacionamento de
dependência entre duas classes mostra que uma instância de uma classe depende
da instância de outra classe. Relacionamentos no qual a modificação de um item
superior ocasiona modificações em itens inferiores.
Generalização
Generalização é o
relacionamento entre uma classe e uma ou mais versões refinadas dela. Facilita
a modelagem pela estruturação de classes e incorpora resumidamente o que é
semelhante e o que é diferente em relação a elas. A herança de operações é uma
boa ajuda durante a implementação como veículo para reutilização de código.
Generalização é utilizada
para referir-se ao relacionamento entre classes, enquanto herança refere-se ao
mecanismo de compartilhamento de atributos e operações utilizando o
relacionamento de generalização.
Multiplicidade
Especifica quantas
instâncias de uma classe relacionam-se a uma única instância de uma classe
associada, por meio do número máximo e mínimo. Depende de pressupostos e de
como são definidas as fronteiras de um problema. Pode ser acrescentada aos
relacionamentos de associação e agregação.
Notação
|
Significado
|
0..1
|
Zero ou uma instância
|
1
|
Somente uma instância
|
0..*
|
Zero ou mais instâncias
|
*
|
Default, número mínimo e
máximo de instâncias são ilimitados
|
1..*
|
Um ou mais instâncias
|
<literal>..*
|
Número exato ou mais de
instâncias
|
Cancelamento de
Características
Uma subclasse pode
cancelar uma característica de uma superclasse pela definição de uma
característica com o mesmo nome. A característica da subclasse refina e se
sobrepõe à característica da superclasse.
Para métodos, é importante
lembrar que não se deve nunca cancelar a assinatura do mesmo. Um cancelamento
deve preservar o tipo e o número de atributos e o tipo de argumentos de uma
operação (método) e o tipo retornado de uma operação (