Diagrama de classe de projeto : especificação de componentes ... ✓
normalmente definidos por questões de ...... Exercício: faça o diagrama de
classes para a.
Derivação Projeto Físico em OO
Diagramas de Classe de Projeto Prof. Tadeu Faria PUC Minas
1
Derivação Projeto Físico em OO Bibliografia GRAIG, Larman. Utilizando UML e Padrões:
uma introdução à análise e ao projeto orientados a objetos. Porto Alegre:Bookman,2005 BEZERRA, Eduardo. Princípios de Análise e Projeto
de Sistemas com UML. Rio de Janeiro: Campus, 2a Edição 2006
2
Classe de Projeto Ilustram as especificações para classes de software e interfaces em um sistema Em relação ao Modelo Conceitual, o DCP apresenta: Possível detalhamento dos atributos e operações Adição dos métodos Possível detalhamento das associações navegabilidade (Adição da direção das associações ) Possível adição de relacionamentos de dependências Possível alteração na estrutura das classes (herança) interfaces com suas operações Possível criação de atributos privados ou protegidos Utilização de padrões de projeto (design patterns) 3
Modelo de Domínio X Modelo de Projeto Modelo conceitual: abstração de conceitos do mundo
real Sale Conceptual Model
POST
Captures 1
1
date isComplete : Boolean time
Concept; abstraction
Diagrama de classe de projeto : especificação de
componentes de software Design Class Diagram
POST
Sale Captures
endSale() enterItem() makePayment()
1
1
date isComplete : Boolean time makeLineItem()
Software component
4
Modelo de Classe de Projeto Modelo de classes de projeto: A criação de classes de projeto deve acontecer em paralelo a criação de diagramas de interação É construído inicialmente nas iterações da fase de elaboração e refinado nas iterações da fase de construção. É passado aos programadores para que eles o implementem 5
*** Especificando os atributos A sintaxe completa da UML para definição de
atributos é: Class Name attribute attribute : type attribute : type = initial value classAttribute /derivedAttribute ... method1() method2(parameter list) : return type abstractMethod() +publicMethod() -privateMethod() #protectedMethod() classMethod() ...
6
Especificando atributos A sintaxe completa da UML para definição de atributos é:
[/] visibilidade nome : tipo = valor inicial
class Cliente { private String nome; private Float debito; private Integer idade; }
7
Especificando os atributos Visibilidade permite definir quais atributos de um
objeto são acessíveis por outros objetos serve para implementar o encapsulamento da estrutura interna da classe O valor inicial de um atributo é automaticamente definido para o atributo sempre que um objeto da classe é instanciado.
8
Especificando os atributos
Um atributo é derivado quando seu valor pode ser obtido a partir dos valores de outros atributos
É representado por uma barra inclinada normalmente definidos por questões de desempenho
Ex: dataNascimento:Data / idade:int 9
Especificando os atributos
Um atributo pode possuir: Escopo de objeto cada objeto tem um valor para cada atributo definido em sua classe Escopo de classe atributos que armazenam um valor comum a todos os objetos da classe, denominado atributo estático pode ser utilizado para implementar regras de negócio. Ex: Em um curso podem estar matriculados até 30 alunos representado com um sublinhado
10
Porque não usar atributos públicos? Deve-se observar que para viabilizar o funcionamento
do mecanismo de persistência é fundamental que os atributos sejam acessados e modificados unicamente pelas operações de alteração e consulta.
Em hipótese alguma outro método, mesmo métodos da
própria classe poderão acessar ou alterar estas variáveis diretamente.
Isso acontece porque quando da implementação do
mecanismo de persistência será necessário ter controle sobre qualquer alteração sofrida pelos objetos, para verificar se estão inconsistentes com o banco de dados.
A melhor forma de garantir isso é sabendo exatamente
quais os pontos do código onde os atributos são modificados.
11
Definição dos atributos: geração de código
class Cliente { private String nome; private Float debito; private Integer idade; }
12
*** Especificando Operações A sintaxe da UML para a assinatura é semelhante a de uma linguagem de programação visibilidade nome(parâmetros): tipo-retorno {propriedades} Onde, para cada parâmetro: direção nome-parâmetro: tipo-parâmetro
13
Especificando operações Operação: um processamento realizado por
(um objeto de) uma classe. – Em termos de implementação: é uma rotina associada
a uma classe.
Na construção do modelo de interações,
operações identificadas na análise são validadas e várias outras operações são identificadas. – Essas operações devem ser adicionadas ao diagrama
de classes e documentadas através da definição de sua assinatura. 14
Especificando operações assinaturas • Durante o projeto é determinada a assinatura de cada operação • argumentos da operação • tipo de retorno da operação
análise curso +adicionaaluno(newaluno)
projeto curso +adicionaaluno(newaluno:aluno*):void
15
Especificando operações
Os parâmetros de uma operação correspondem a informações que esta recebe quando é executada
cada parâmetro da lista tem a seguinte sintaxe: direção nome-parâmetro: tipo-parâmetro
Direção Significado in
Parâmetro de entrada
out
Parâmetro de saída.
inout
Parâmetro de entrada e de saída. 16
Especificando operações • Durante a análise são criadas operações para implementar o comportamento expresso nos casos de uso • durante o projeto: • são adicionadas a essas classes os detalhes de implementação • são acrescentadas operações adicionais para tornar as classes mais completas
17
Especificando operações
Acrescentando atributos, operações e informações de tipos às classes
18
Operações de criação e destruição Operações utilizadas freqüentemente nas
interações entre objetos. Os parâmetros de uma operação de criação
servem para iniciar atributos do objeto. – Regra prática: se o valor de um atributo é
essencial para o significado do objeto, é mais adequado iniciar o seu valor logo na criação do objeto.
Operações de destruição servem para liberar
memória alocada dinamicamente. 19
Operações de criação e destruição Operações de criação são identificadas na
construção dos diagramas de interação. Operações de criação também são
utilizadas para definir o estado inicial de um objeto que passa por um conjunto de estados relevantes durante a sua existência.
20
Operações de criação e destruição Métodos create Métodos de instanciação (construtores) específicos para cada
linguagem de programação Normalmente omitidos no diagrama de classe Métodos de acesso get e set de atributos Omitidos no diagrama para reduzir ruído (2N métodos
desinteressantes para cada N atributos) Métodos de coleção (multiobjects) Parte da definição da coleção (classes de biblioteca do tipo
container: Vetor, Hashtable, etc.) Omitidos no diagrama para reduzir ruído
21
Operações para alterar e acessar:geração código class Cliente { private String nome; private Float debito; private Integer idade; public void setNome(String nome) { this.nome = nome; } public void setDebito(Float debito) { this.debito = debito; } public void setIdade(Integer idade) { this.idade = idade; } public String getNome() { return nome; } public Float getDebito() { return debito; } public Integer getIdade() { return idade; } } 22
Membros estáticos Membros estáticos são representados no
diagrama de classes por declarações sublinhadas. – Atributos estáticos (variáveis de classe) são
aqueles cujos valores valem para a classe de objetos como um todo. – Diferentemente de atributos não-estáticos (ou variáveis de instância), cujos valores são particulares a cada objeto.
– Métodos estáticos são os que não precisam da
existência de uma instância da classe a qual pertencem para serem executados. – Forma de chamada: NomeClasse.Método(argumentos) 23
*** Relacionamentos classes Na UML, há três tipos de relacionamentos entre
objetos: – Associações – Dependências – Generalizações
No modelo de classes de domínio, os
relacionamentos entre objetos foram identificados como associações. 24
*** Associações Associação : São relacionamentos estruturais entre
instâncias e especificam que objetos de uma classe estão ligados a objetos de outras classes. Podemos ter associação uniária , binária , etc.
A associação pode existir entre classes ou entre objetos.
Uma associação entre a classe Professor e a classe disciplina (um professor ministra uma disciplina) significa que uma instância de Professor (um professor específico) vai ter uma associação com uma instância de Disciplina. Esta relação significa que as instâncias das classes são conectadas, seja fisicamente ou conceitualmente.[Nicolas Anquetil] 25
*** Associações Sempre que um atributo de uma classe não é de
tipo primitivo, temos uma associação desta classe com alguma outra. As associações do DCP são transformadas em
variáveis de instância, da mesma forma que os atributos, e terão métodos para alteração e consulta. Os atributos geram sempre variáveis cujos tipos são básicos (alfanuméricos) As associações geram tipos que são classes de objetos ou estruturas de dados. Considerando as diferentes multiplicidades de papel e outras características das associações, haverá algumas distinções a fazer quanto aos métodos associados.
26
Associações devem implementar no mínimo Um método para criar
ou redefinir a associação Um método para remover a associação (exceto para associações para 1) Um método para obter objetos associados
class ItemDeEmprestimo { private Emprestimo emprestimo; public ItemDeEmprestimo(Emprestimo emprestimo) { this.associaEmprestimo(emprestimo ) } public void associaEmprestimo(Emprestimo emprestimo) { this.emprestimo = emprestimo; } public Emprestimo getEmprestimo() { return emprestimo; } }
27
Associações:exemplo 1 Suponhamos uma classe
Cliente com dois atributos apenas, código e dataDeNascimento. O código é um número inteiro que identifica o cliente, portanto, um tipo primitivo (int), mas a data de nascimento é do tipo Data
Cliente cod : Integer dataNasc : Data
Data
28
Associações:exemplo 1 Classe data public class Data { private int dia; private int mes; private int ano; } Classe cliente public class Cliente { private int codigo; private Data dataDeNascimento; public Cliente(int umCodigo, int umDia, int umMes, int umAno) { codigo = umCodigo; dataDeNascimento = new Data(umDia, umMes, umAno); } .... }
Uma outra alternativa é criar o objeto cliente sem uma data de nascimento e inserila mais tarde. Neste caso, precisamos um outro construtor (sobrecarregado) com um só parâmetro para o codigo: public Cliente(String umCodigo) { codigo = umCodigo; dataDeNascimento = null; 29
Associações:exemplo 2 public class Cliente {
Suponha uma classe cliente relacionada com uma classe dependente
Cliente nome : String apelido : String endereco : String0..*
//Declaração dos atribultos private String nome; private String endereco; private String apelido; protected Dependente dependente; //Construtor padrão public Cliente(){} //Construtor com atributos public Cliente(String nome, String endereco,String apelido ){ this.nome = nome; this.endereco = endereco; this.apelido = apelido; } //Get public String getApelido() { return apelido; } public String getEndereco() { return endereco; } public String getNome() { return nome; } public Dependente getDependente() { return dependente; } //Set public void setApelido(String apelido) { this.apelido = apelido; } public void setEndereco(String endereco) { this.endereco = endereco; } public void setNome(String nome) { this.nome = nome; } public void setDependente(Dependente dependente) { this.dependente = dependente; }
Dependente 1
nome : String numero : Integer
30 }
Associações:exemplo 2
public class Dependente { private String nomeDep; private double numero; //Criação de uma lista de clientes dentro de dependentes //neste caso o dependete possui um relacionamento 1 para n //ou seja o cliente pode ser de vários dependentes protected List listaCliente = new ArrayList(); //Construtor padrão public Dependente() {} //Construtor com argumentos public Dependente(String nomeDep, double numero){ this.nomeDep = nomeDep; this.numero = numero; } //Get public String getNomeDep() { return nomeDep; } public double getNumero() { return numero; } public List getListaCliente() { return listaCliente; } //Set public void setNomeDep(String nomeDep) { this.nomeDep = nomeDep; } public void setNumero(double numero) { this.numero = numero; } public void setListaCliente(List listaCliente) { this.listaCliente = listaCliente; } }
31
Associações:exemplo 2 public class TesteClasses { public static void main(String[] args) { //utilizado o construtor com argumentos onde o double é representado por D Dependente dependente1 = new Dependente("João",1D); Dependente dependente2 = new Dependente("Maria", 2D); Cliente cliente = new Cliente("Cliente pai","rua que sobe e desce","cli"); Cliente cliente2 = new Cliente("Cliente mãe","rua Belo Horizonte","cli 2"); cliente.setDependente(dependente1); cliente2.setDependente(dependente2); cliente.imprimeDados("dependente 2 --> ", cliente); //Parte 2 removendo a associação do dependente com cliente 2 cliente2.setDependente(null); //Parte 3 criando a associação sem dependente Cliente clienteNull = new Cliente("Cliente pai","rua que sobe e desce","cli"); Cliente clienteNull2 = new Cliente("Cliente mãe","rua Belo Horizonte","cli 2"); clienteNull.setDependente(null); clienteNull2.setDependente(null); //parte 4 Cliente clienteNumero1 = new Cliente("Cliente 1","endereco 1", "cle 1"); Cliente clienteNumero2 = new Cliente("Cliente 2","endereco 2", "cle 2"); Cliente clienteNumero3 = new Cliente("Cliente 3","endereco 3", "cle 3"); Cliente clienteNumero4 = new Cliente("Cliente 4","endereco 4", "cle 4"); //Associação do dependente para n clientes Dependente dependenteDeTodos = new Dependente("dependente de todos", 10D); dependenteDeTodos.getListaCliente().add(clienteNumero1); dependenteDeTodos.getListaCliente().add(clienteNumero2); dependenteDeTodos.getListaCliente().add(clienteNumero3); dependenteDeTodos.getListaCliente().add(clienteNumero4); //iteração na lista de clientes dentro do dependente usado //a nomenclatura do For moderno consiste em primeiro a Classe pelo qual será iterado //o objeto desta classe sendo que o garbaje collector retira do heap assim que termina o for //e a coleção para iteração for (Cliente clienteIteracao : dependenteDeTodos.getListaCliente()) { System.out.println("o cliente pertence ao cliente --> " + clienteIteracao.getNome()); } }}
32
Navegabilidade de associações Navegabilidade é a propriedade do papel que indica
que é possível navegar unidirecionalmente por meio da associação de objetos da classe de origem para a classe destino A navegabilidade implica geralmente em visibilidade
por atributo (associação) A maioria das associações no diagrama de classe de
projeto deve estar adornada com setas de navegabilidade
33
Navegabilidade de associações Associações, agregações e composições
podem ser bidirecionais e unidirecionais. Uma associação bidirecional indica que há um
conhecimento mútuo entre os objetos associados. Na UML, associações são, por omissão,
navegáveis em ambos os sentidos. Uma associação unidirecional é representada
adicionando-se um sentido à seta da associação.
34
Navegabilidade de associações No modelo de classes de projeto, a
navegabilidade de todas as associações deve ser definida. – Algumas associações permanecem bidirecionais. – Se não houver essa necessidade, recomenda-se
transformar a associação em unidirecional.
A escolha do sentido da navegabilidade pode
ser feita através dos diagramas de interação. – Mensagens influenciam na existência ou não de
navegabilidade em um sentido.
35
Navegabilidade de associações Na análise, as associações são bi-direcionais No projeto, uma associação pode ser uni-direcional; uma seta
é adicionada à associação para mostrar que a navegação é em uma direção C lie n te
P e d id o 0 ..* O cliente pode ‘conversar’ com pedido O pedido não pode ‘conversar’ com o cliente
A necessidade de navegação é revelada por casos de uso e cenários. dada uma instância de A, precisamos encontrar todas as instâncias
associadas da classe B ou vice-versa?
36
Navegabilidade de associações Situações comuns que indicam uma
necessidade de definir uma associação com um adorno de navegabilidade de A para B – A envia uma mensagem para B – A cria uma instância B – A precisa manter uma conexão com B
37
Navegabilidade de associações : Loja
:
cp : CatalogoProduto
: EspecificaçãoProduto
ep : EspecificaçãoProduto
: Registro
criar( ) criar( ) criar( ) carregarEspProd( ) criar(id : , preco : , descricao : )
criar(cp : )
Cat alogoP rodut o Loja c riar() 1
Observando o diagrama é discernível que Loja tenha uma associação permanente com instâncias de registro e de CatalogoProduto que criou e que CatalogoProduto também tenha uma conexão permanente com Especificaçãoproduto
us a 1
1
c riar() c arregarE s pP rod() 1
ab riga
po s s ui
1 Regis tro
1..* E s pec ific aç ão P rodut o
c riar()
c riar() c riar()
38
Associação unidirecional para 1 A associação unidirecional para 1, deve ser
armazenada em uma variável de instância na classe de origem da associação e seu tipo deve ser a classe de destino. Assim, uma associação unidirecional para 1 de ItemDeEmprestimo para Emprestimo corresponderá a uma variável de instância na classe ItemDeEmprestimo declarada com tipo Emprestimo.
39
Associação unidirecional para 1 Como associação é estritamente para 1, então não é
possível destruir a associação, e, portanto, o método para destruir a associação não deve ser implementado. Como a associação para 1 é obrigatória para o objeto na origem, o método criador da classe deve ter como parâmetro o elemento a ser associado para que desde o momento da criação todas as instâncias da classe na origem da associação estejam consistentes.
40
Associação unidirecional para 1
class ItemDeEmprestimo { private Emprestimo emprestimo; public ItemDeEmprestimo(Emprestimo emprestimo) { this.associaEmprestimo(emprestimo ) } public void associaEmprestimo(Emprestimo emprestimo) { this.emprestimo = emprestimo; } public Emprestimo getEmprestimo() { return emprestimo; } }
41
Associação Unidirecional para 0..1 É possível destruir a associação e, portanto
deve ser implementado o método correspondente. Não é necessário passar um objeto como parâmetro para o método criador, pois a associação para 0..1 não é obrigatória.
42
Associação Unidirecional para 0..1
class Venda { private Pagamento pagamento; public Venda() { } public void associaPagamento(Pagamento pagamento) { this.pagamento = pagamento; } public void desassociaPagamento() { this.pagamento = null; } public Pagamento getPagamento() { return pagamento; } }
43
Associação Unidirecional para * Corresponde à implementação de um
conjunto
44
Associação Unidirecional para *
class Cliente { private Set emprestimos = new HashSet(); public Cliente () { } public void adicionaEmprestimo(Emprestimo emprestimo) { this.emprestimos.add(emprestimo); } public void removeEmprestimo(Emprestimo emprestimo) { this.emprestimos.remove(emprestimo); } public Set getEmprestimos () { return Collections.unmodifiableSet(emprestimos); } }
45
Tratando classes de associação Durante o projeto, classes de associação
evoluem para:
– Tranformação de uma classe de associação em uma
classe interposta entre as classes originais; – Estabelecimento de associações com mutiplicidade apropriada entre a classe de associação e as outras duas classes – Projeto de novas associações. A navegação pode ser bi-direcional ou uni-direcional. Curso
Aluno 1..*
1..*
Boletim
Curso
Boletim 1
*
Aluno *
1
46
Associação Unidirecional com Classe de Associação class Pessoa { private Map empresas = new HashMap();
}
public Pessoa() { } public void adicionaEmpresa(Empresa empresa) { this.empresas.put(empresa, new Emprego()); } public void removeEmpresa ( Empresa empresa ) { this.empresas.removeKey(empresa); } public void removeEmprego ( Emprego emprego ) { this.empresas.removeValue(emprego); } public Set getEmpresas () { return empresas.keys() ; } public Set getEmpregos () { return empresas.values() ; } public Emprego getEmpregoNaEmpresa ( Empresa empresa) { return empresas.at(empresa) }
47
Associação Unidirecional com Multiplicidade 1 na Origem a destruição da associação só será possível
quando o objetivo for também destruir o objeto no destino da associação No caso de associações de 1 para 0..1 ou de 1 para 1 deve-se tomar este mesmo cuidado em relação à operação de criação/redefinição de associação
48
Associação Bidirecional class Cliente { private Set emprestimos = new HashSet(); public Cliente () {} public void adicionaEmprestimoAux(Emprestimo emprestimo) { emprestimos.add(emprestimo); } public void removeEmprestimoAux(Emprestimo emprestimo) { emprestimos.remove(emprestimo); } public void adicionaEmprestimo(Emprestimo emprestimo) { if (emprestimo.getCliente() != null) { emprestimo.getCliente().removeEmprestimoAux(emprestimo); }; this.adicionaEmprestimoAux(emprestimo); emprestimo.associaClienteAux(this); } public void removeEmprestimo(Emprestimo emprestimo) { this.removeEmprestimoAux(emprestimo); emprestimo.destroi(); } public Set getEmprestimos() { return emprestimos; } }
49
class Emprestimo { private Cliente cliente; public Emprestimo(Cliente cliente) { this.associaCliente(cliente); } public void associaClienteAux(Cliente cliente) { this.cliente = cliente; } public void associaCliente(Cliente cliente) { if (this.cliente != null) { this.cliente.removeEmprestimoAux(this); }; this.associaClienteAux(cliente); cliente.adicionaEmprestimoAux(this); } public Cliente getCliente() { return cliente; } }
50
agregações Agregação Regular - tipo de associação ( é parte de
, todo/parte) onde o objeto parte é um atributo do todo ; onde os objetos partes somente são criados se o todo ao qual estão agregados seja criado. Pedidos é composto por itens de pedidos. Composição - Relacionamento entre um elemento ( o todo) e outros elementos (as partes) onde as parte só podem pertencer ao todo e são criadas e destruídas com ele.
51
Navegabilidade de agregações Navegabilidade em Agregações: Uma agregação também pode ser uni-direcional
durante o projeto. Os relacionamentos podem ser de dois tipos: Por referência (agregation) – implica que os tempos de vida dos objetos relacionados podem ser independentes; Por valor (composition) – implica que os objetos são criados e destruídos em consequencia da criação ou destruição de um outro objeto.ItemPedido Pedido 0..* 52
Relacionamentos de dependência O relacionamento de dependência indica que uma classe depende (ou
tem conhecimento) dos serviços fornecidos por uma outra classe. São relacionamentos de utilização no qual uma mudança na
especificação de um elemento pode alterar a especificação do elemento dependente. A dependência entre classes indica que os objetos de uma classe usam serviços dos objetos de outra classe. – características de implementação. É útil para representar as visibilidades (slides a seguir) não mostradas
no diagrama de classes, isto é: – Dependência por variável global. – Dependência por variável local. – Dependência por parâmetro.
53
relacionamentos de dependência Representado através de uma linha direcionada e
tracejada ligando as classes envolvidas. A direção é da classe dependente (cliente) para a classe da qual ela depende (fornecedora). Estereótipos: global, local, parameter. Um relacionamento de dependência indica que: Operações da classe cliente criam objetos da classe fornecedor; Operações da classe cliente possuem métodos cuja classe de retorno ou seus argumentos são instâncias da (ou se referenciam à) classe fornecedor 54
relacionamentos de dependência Exemplo
55
Visibilidade entre Objetos Capacidade de um objeto “ver” ou ter uma referência
para outro objeto – Necessária para comunicação (envio de mensagens) entre
objetos
Relacionada a questão de escopo: uma instância está
dentro do escopo do outro Para um objeto A enviar uma mensagem para um objeto B, B deve ser visível para A Estabelece um relacionamento de dependência que
indica que uma classe depende (ou tem conhecimento) dos serviços fornecidos por uma outra classe. 56
Visibilidade entre Objetos Quatro maneiras de B ser visível para A: – Visibilidade de atributo (associação) — B é um atributo de A (as classes de dois objetos estão associadas) – Visibilidade de parâmetro — B é um parâmetro de um método de A (quando um objeto recebe outro como parâmetro em um de seus métodos) – Visibilidade declarada localmente — B é declarado como objeto local de um método de A (quando um objeto recebe outro como retorno de um método – Visibilidade global — B é de algum modo visível globalmente 57
Visibilidade de Atributo (associação) Existe de A para B
quando B é um atributo de A – Permanente — persiste
enquanto A e B existirem
58
Visibilidade por Parâmetro Existe de A para B quando B é passado como um
parâmetro para um método de A – Temporária — persiste apenas dentro do escopo do método
de A (permanente se B é atribuído a um atributo de A)
59
Visibilidade por Parâmetro Msg( c) :Emprestimo
> 60
Visibilidade Local Existe de A para B quando B é declarado como um objeto local dentro de um método de A – Temporária — persiste apenas dentro do escopo do método de A (permanente se B é atribuído a um atributo de A) – Duas maneiras comuns de alcançar: – 1. Criar nova instância e atribuir para variável local – 2. Atribuir objeto de retorno de um método para variável local
61
Visibilidade local f:=msg( c) :EstadoDeItemDeEmprestimo
ItemDeEmprestimo
>
62
Visibilidade Global Existe de A para B quando B é global para A – Permanente — persiste enquanto A e B existirem Forma menos comum de visibilidade em
sistemas desenvolvidos utilizando OO
– Maneira mais comum (mas não recomendada) de
atingir é atribuir nova instância a uma variável global
Alternativa recomenda: – Padrão Singleton (GoF)
63
Notação de Visibilidade na UML Uso opcional de “estereótipos” específicos
64
Detalhes de visibilidade de membros de classes em UML Significado
Símbolo
Visibilidade
Pública
+
Qualquer objeto externo pode obter acesso ao membro, desde que tenha uma referência para aclasse em que o membro está definido
Protegida
#
Visível às subclasses
Privativa
_
Invisível externamente a classe em que está definido
65
Transformação de associações em dependências Na passagem para o modelo de projeto cada
associação deve ser considerada para identificar se ela pode ser transformada em dependências. Razão: aumentar o encapsulamento das
classes – Dependência por atributo torna as classes
envolvidas mais dependentes uma da outra. – Quanto menos dependências estruturais houver
no modelo de classes, maior é o encapsulamento das classes constituintes.
66
Transformação de associações em dependências Associações que ligam classes de entidade permanecem como
associações. Associações entre controladores e classes de entidade:
bastante suscetíveis à transformação. Associações entre classes de fronteira e controladores: classe de fronteira para esse ator: essa classe pode manter
um relacionamento estrutural com o controlador (composição). classes de fronteira para equipamentos ou outros sistemas:
interfaces, dependência não estrutural.
67
*** Relacionamento de Herança durante o projeto, as hierarquias de heranças são
refinadas para: aumentar o reuso incorporar classes de implementação incorporar bibliotecas de classes disponíveis
diagramas de análise são revisados para identificar
similaridades em atributo operações associações
novas superclasses são definidas para conter elementos
comuns 68
Relacionamento de Herança Na modelagem de classes de projeto, há
diversos aspectos relacionados ao de relacionamento de herança. – Tipos de herança – Classes abstratas – Operações abstratas – Operações polimórficas – Interfaces – Acoplamentos concreto e abstrato – Reuso através de delegação e através de
generalização – Classificação dinâmica
69
Tratamento hierarquias de herança
Exercício: faça o diagrama de classes para a seguinte descrição: –
–
– –
Em um sistema de ofertas de emprego na internet uma empresa pode ofertar diversas vagas. Uma vaga esta relacionada a somente uma empresa. Um candidato, previamente cadastrado, pode fazer inscrição em uma vaga. Um candidato pode fazer inscrição em mais de uma vaga. O candidato selecionado recebe uma matricula. No processo de avaliação de contratação, um funcionário recebe diversas ocorrências empresa e faz a inscrição.
Refaça o diagrama considerando possíveis reestruturações das classes para otimizar o modelo
70
Tipos de herança Com relação à quantidade de superclasses
que certa classe pode ter. – herança múltipla – herança simples
Com relação à forma de reutilização
envolvida. – Na herança de implementação, uma classe reusa
alguma implementação de um “ancestral”. – Na herança de interface, uma classe reusa a interface (conjunto das assinaturas de operações) de um “ancestral” e se compromete a implementar essa interface.
71
Herança ⇒ Hierarquia de Classes Em Java, Object é a superclasse de todas as classes.
Object Animal peso
peso é uma variável de instância que está presente em todos os objetos criadas para as classes Animal, Mamífero, Ave e Réptil.
locomover ()
Mamífero Mamífer peso o comer()
Ave Ave peso andar() locomover( voar()
Réptil Réptil peso andar() locomover( nadar()
voar()
nadar()
)
)
72
Herança ⇒ Hierarquia de Classes Object Animal peso
peso é uma variável de instância que está presente em todos os objetos criadas para as classes Animal, Mamífero, Ave e Réptil.
locomover( )
Mamífero comer()
Ave pardal = new Ave(); pardal.peso = 700;
Ave
Réptil
locomover( )
locomover( )
voar()
nadar()
Mamifero boi = new Mamifero() boi.peso = 30000; boi.locomover(); // boi.voar(); não existe!
73
Herança
Busca Dinâmica de Métodos Mamifero boi = new Mamifero() boi.peso = 30000; boi.andar(); boi.locomover();
Object Animal peso
boi this
locomover( )
Mamífero comer()
peso = 30000 0
Ave
Réptil
locomover( )
locomover( )
voar()
nadar()
74
Herança Estender uma classe causa dois efeitos: – criação de um subtipo. – todas as declarações da classe estendida (superclasse)
são incluídas na subclasse, a menos que elas tenham sido sobrepostas.
75
Definindo a Superclasse Forma geral: – class extends SuperClass
– é permitido apenas uma superclasse. não há herança múltipla em Java. – cada classe apresenta exatamente uma superclasse. exceção: java.lang.Object – caso não exista a cláusula extends, então, assumese que a superclasse é Object.
76
Exemplo de Herança class Animal { int peso; void locomover() { /* movimentação do animal */ } } class Mamifero extends Animal { void comer() }
Sobreposição de método!
class Ave extends Animal { void locomover() { } void voar() { } }
77
A Classe Object A classe java.lang.Object forma a raiz da
hierarquia de classes. – Direta ou indiretamente, toda classe é uma subclasse de
Object.
Object define alguns métodos úteis, incluindo: – String toString(); – boolean equals(Object outro).
78
Classes abstratas Usualmente, a existência de uma classe se justifica
pelo fato de haver a possibilidade de gerar instâncias a partir da mesma. – Essas classes são chamadas de classes concretas. No entanto, podem existir classes que não geram instâncias “diretamente”. – Essas classes são chamadas de classes abstratas. Classes abstratas são usadas para organizar hierarquias gen/spec. – Propriedades comuns a diversas classes podem ser organizadas e definidas em uma classe abstrata a partir da qual as primeiras herdam. Também propiciam a implementação do princípio do polimorfismo. 79
Classes abstratas (cont) Na UML, uma classe abstrata pode ser representada de duas maneiras alternativas: Com o seu nome em itálico. Qualificando-a com a propriedade {abstract}
Classe abstratas: Não podem ser instanciadas Não pode utilizar operador new Palavra chave: abstract.
public abstract class ContaBancaria { public void sono() { } } 80
Operações abstratas Uma classe abstrata possui ao menos uma operação abstrata, que corresponde à especificação de um serviço que a classe deve fornecer (sem método). Uma classe qualquer pode possuir tanto operações abstratas, quanto operações concretas (ou seja, operações que possuem implementação). Entretanto, uma classe que possui pelo menos uma operação abstrata é, por definição abstrata, abstrata.
Uma operação abstrata definida com visibilidade pública em uma classe também é herdada por suas subclasses. Quando uma subclasse herda uma operação abstrata e não fornece uma implementação para a mesma, esta classe também é abstrata. 81
Operações abstratas (cont) Na UML, a assinatura de uma operação abstrata é definida em itálico.
82
Operações Abstratas Não possui corpo. Apresenta apenas a definição seguida de “;” Apresenta o modificador abstract. public abstract class Animal { public int peso; public abstract void locomover(); }
83
Exemplo de Abstração public abstract class FiguraGeometrica { public abstract double area(); public abstract double perimetro(); } public class Retangulo extends FiguraGeometrica { protected double w, h; public Retangulo() { this(0.0,0.0); } public Retangulo(double l, double a) { w = l; h = a; } public double area() { return w*h; } public double perimetro() { return 2*w*h; } }
84
Polimorfismo Conceito complementar a herança que permite enviar a mesma mensagem a objetos distintos, onde cada objeto responde da maneira mais apropriada para a sua classe.
85
Operações polimórficas Uma subclasse herda todas as propriedades de sua
superclasse que tenham visibilidade pública ou protegida. Entretanto, pode ser que o comportamento de alguma operação herdada seja diferente para a subclasse. Nesse caso, a subclasse deve redefinir o comportamento da operação. – A assinatura da operação é reutilizada. – Mas, a implementação da operação (ou seja, seu método) é diferente. Operações polimórficas são aquelas que possuem mais de uma implementação. 86
Operações polimórficas (cont) Operações polimórficas possuem sua assinatura definida em
diversos níveis de uma hierarquia gen/spec. – A assinatura é repetida na(s) subclasse(s) para enfatizar a redefinição de implementação. – O objetivo de manter a assinatura é garantir que as subclasses tenham uma interface em comum. Operações polimórficas facilitam a implementação. – Se duas ou mais subclasses implementam uma operação polimórfica, a mensagem para ativar essa operação é a mesma para todas essas classes. – No envio da mensagem, o remetente não precisa saber qual a verdadeira classe de cada objeto, pois eles aceitam a mesma mensagem. – A diferença é que os métodos da operação são diferentes em cada subclasse.
87
Operações polimórficas (cont) A operação obterPagamento é polimórfica.
88
Operações polimórficas (cont) Operações polimórficas também podem
existir em classes abstratas.
89
Operações polimórficas (cont) Operações polimórficas implementam o
princípio do polimorfismo, no qual dois ou mais objetos respondem a mesma mensagem de formas diferentes. ContaCorrente cc; ContaPoupanca cp; ... List contasBancarias; ... contasBancarias.add(cc); contasBancarias.add(cp); ... for(ContaBancaria conta : contasBancarias) { conta.aplicarJuros(); } ... 90
Operações polimórficas (cont) Animal
Exemplo
sono() comida()
gato
cachorro
tigre
Lobo
Leao
Animal[] animais[] = new Animal[5];Os métodos são executados de acordo com o objeto animais[0] = new Cachorro(); animais[1] = new gato(); animais[2] = new Lobo(); animais[3] = new tigre(); animais[4] = new leao(); for (int i = 0; i < animais.length(); i++) { animais[i].comida(); animais[i].sono(); }
91
Polimorfismo Existem três tipos de polimorfismos em Java: – Sobrecarga – Sobreposição (entre superclasse e subclasse) – Generalização (subtipo & coerção)
92
Polimorfismo SOBRECARGA – Métodos (procedimentos) com o mesmo nome, mas com
argumentos diferentes. – Identificados por:
– nome do método; – tipo de dados dos parâmetros.
93
Polimorfismo SOBREPOSIÇÃO – Métodos (procedimentos) com o mesmo nome, mas com
funcionalidades diferentes.
– Permite que uma subclasse herde um método da superclasse
e implemente-o de forma diferente.
– Identificados por:
– classe do objeto. – conteúdo do objeto.
94
Sobrecarga x Sobreposição class Ave extends Animal { private int altura, velocidade; Ave() { altura = 0; velocidade = 0; } void locomover() { velocidade = 2; } void locomover(int vel); { velocidade = vel; } void parar() { andar(0); } void voar() { altura = 10; velocidade = 30; } }
{
Ave.locomover() sobrepõe o método de Animal.locomover( ). locomover() também é sobrecarregado na classe Ave.
95
Sobreposição de Variáveis Ao sobrepor variáveis, podemos referenciar a
variável da superclasse através da palavra super.
class A { int a; A() { a = 1; } }
class B extends A { int a, b; B() { super(); a = super.a; b = 2; } } 96
Sobreposição de Métodos Um
método da superclasse também pode ser invocado usando a palavra super.
class A { int i = 1; int f() { return i;} }
class B extends A { int i; //sobrepõe atributo int f() //sobrepõe { f() de A i = super.i + 1; //A.i return super.f() + //A.f() } }
o i de A o método
i;
97
Interfaces Uma interface entre dois objetos compreende
um conjunto de assinaturas de operações correspondentes aos serviços dos quais a classe do objeto cliente faz uso. Uma interface pode ser interpretada como um contrato de comportamento entre um objeto cliente e eventuais objetos fornecedores de um determinado serviço. – Contanto que um objeto fornecedor forneça
implementação para a interface que o objeto cliente espera, este último não precisa conhecer a verdadeira classe do primeiro.
98
Interfaces (cont.) Interfaces são utilizadas com os seguintes objetivos: 1. Capturar semelhanças entre classes não relacionadas sem forçar relacionamentos entre elas. 2. Declarar operações que uma ou mais classes devem implementar. 3. Revelar as operações de um objeto, sem revelar a sua classe. 4. Facilitar o desacoplamento entre elementos de um sistema.
Nas LPOO modernas (Java, C#, etc.), interfaces são
definidas de forma semelhante a classes. – Uma diferença é que todas as declarações em uma interface
têm visibilidade pública. – Adicionalmente, uma interface não possui atributos, somente declarações de assinaturas de operações e (raramente) constantes. 99
Interfaces (cont.) Em JAVA, classes só podem ter um ancestral direto, ou seja, só
podem ser derivadas de uma única classe (embora esta possa ser derivada de outra e assim por diante). Existem situações, porém, onde pode ser necessário que uma classe herde características de mais de uma “superclasse” simultaneamente. Como a herança múltipla não é permitida em JAVA, a linguagem oferece a o conceito de interface como opção. Uma interface define um conjunto de métodos que uma classe deve implementar mas não define como esses métodos devem ser implementados. Define, na verdade, uma lista de métodos que toda a classe que segue determinada interface deve prover.
10 0
Interfaces (cont) Notações para representar interfaces na
UML:
– A primeira notação é a mesma para classes. São
exibidas as operações que a interface especifica. Deve ser usado o estereótipo . – A segunda notação usa um segmento de reta com um pequeno círculo em um dos extremos e ligado ao classificador. – Classes clientes são conectadas à interface através de um relacionamento de notação similar à do relacionamento de dependência.
10 1
Interfaces (cont) Exemplo: ICMS pode ser diferenciado dependendo do tipo de produto. Para evitar que um programa chame cada classe específica para calcular o ICMS, pode-se criar uma interface que vai ser acionada pelo programa. A implementação dela está nas classes específicas de cada produto. ; public interface ICMS { static final double aliquota = 0.9; public abstract double meuICMS(); }
usa
Classe cliente
IMPLEMENTA class Carro implements ICMS { String fabricante, modelo; int ano, vel_max, peso; float preco; int num_rodas = 4; int num_portas; public double meuICMS() { return 0.17 * preco; } }
class Consultoria implements ICMS { double valor; public double meuICMS() { return 0.1 * valor; }
10 2
Diferenças entre Classes abstratas e Interfaces Uma interface é como um conjunto de regras
(contrato) definidas e que devem ser rigorosamente seguidas (implementadas). – Interface é quando você apenas quer definir um
"contrato" que as classes devem realizar (implementar) – uma interface é uma maneira de descrever o que a classe vai fazer, ao invés de como ela faria
10 3
Diferenças entre Classes abstratas e Interfaces A herança possibilita o reaproveitamento de código,
onde cada subclasse herda as características da super classe. Uma classe abstrata pode conter métodos implementados e métodos não-implementados, ou seja, abstratos. – Em uma interface, todos os métodos são abstratos – Uma interface é como uma classe 100% abstrata.
com uma classe abstrata, pode-se criar os métodos
com a lógica em comum para todos os casos, e deixar os métodos dependentes de implementação que serão abstract - serem feitos pelas subclasses. – Toda classe que possui métodos abstratos é
automaticamente abstrata e deve ser declarada como tal
10 4
Diferenças entre Classes abstratas e Interfaces Classes abstratas: –
Podem possuir atributos não estáticos
–
Podem implementar alguns métodos
Uma classe só pode herdar de apenas outra classe. Logo, não podemos
ter uma mesma classe que herde de duas classes abstratas. –
Não pode possuir atributos não estáticos
–
Não pode implementar nenhum método
Uma classe pode implementar mais de uma interface. Ou seja,
possibilita boa parte dos recursos de herança múltipla sem problemas de conflitos de nomes dos atributos. public class MyClass extends SuperClass1 implements Interface1, Interface2, Interface3
10 5
Diferenças entre Classes abstratas e Interfaces uma classe abstrata é uma classe "incompleta", onde
define-se o esqueleto base para as classes filhas e, ao contrario de uma Interface, pode-se ter também métodos reais, que façam algo. –
Util para casos onde quer prover as funcionalidades básicas e deixar a especializacão/criação de outros métodos para as classes mais especificas..
Uma interface é utilizada quando não existe a
necessidade das classes derivadas herdarem métodos já implementados. Sugestão: Use classes abstratas somente quando realmente não puder usar interfaces.
10 6
Diferenças entre Classes abstratas e Interfaces Diferentemente das classes, uma interface
pode herdar de mais de uma interface Para que usar interfaces?
– Uma interface é utilizada quando não existe a
necessidade das classes derivadas herdarem métodos já implementados – Para deixar o código mais flexível, e possibilitar a mudança de implementação sem maiores traumas. – Elas também trazem vantagens em não acoplar as classes. Uma vez que herança através de classes traz muito acoplamento, muitos autores clássicos dizem que em muitos casos herança quebra o encapsulamento. 10 7
Especificação de classes de fronteira Não devemos atribuir a essas classes
responsabilidades relativas à lógica do negócio. – Classes de fronteira devem apenas servir como um ponto de
captação de informações, ou de apresentação de informações que o sistema processou. – A única inteligência que essas classes devem ter é a que permite a elas realizarem a comunicação com o ambiente do sistema.
Há diversas razões para isso: – Em primeiro lugar, se o sistema tiver que ser implantado em
outro ambiente, as modificações resultantes sobre seu funcionamento propriamente dito seriam mínimas. – Além disso, o sistema pode dar suporte a diversas formas de interação com seu ambiente (e.g., uma interface gráfica e uma interface de texto). – Finalmente, essa separação resulta em uma melhor coesão.
10 8
Especificação de classes de fronteira Durante a análise, considera-se que há uma única classe de
fronteira para cada ator. No projeto, algumas dessas classes podem resultar em várias outras. Interface com seres humanos: projeto da interface gráfica produz o detalhamento das classes. Outros sistemas ou equipamentos: devemos definir uma ou mais classes para encapsular o protocolo de comunicação. – É usual a definição de um subsistema para representar a comunicação com outros sistemas de software ou com equipamentos. – É comum nesse caso o uso do padrão Façade (mais adiante) O projeto de objetos de fronteira é altamente dependente da natureza do ambiente…
10 9
Especificação de classes de fronteira Clientes WEB clássicos – Classes de fronteira são representadas por páginas HTML que,
muitas vezes, representam sites dinâmicos. Clientes móveis – Classes de fronteira implementam algum protocolo específico com o ambiente. – Um exemplo é a WML (Wireless Markup Language). Clientes stand-alone – Nesse caso, é recomendável que os desenvolvedores pesquisem os recursos fornecidos pelo ambiente de programação sendo utilizado. – Um exemplo disso é o Swing/JFC da linguagem Java. Serviços WEB (WEB services) – Um serviço WEB é um uma forma de permitir que uma aplicação forneça seus serviços (funcionalidades) através da Internet.
11 0
Especificação de classes de entidade A maioria das classes de entidade normalmente permanece na
passagem da análise ao projeto. – Na verdade, classes de entidade são normalmente as primeiras classes a serem identificadas, na análise de domínio. Durante o projeto, um aspecto importante a considerar sobre classes de entidade é identificar quais delas geram objetos que devem ser persistentes. – Para essas classes, o seu mapeamento para algum mecanismo de armazenamento persistente deve ser definido . Um aspecto importante é a forma de representar associações, agregações e composições entre objetos de entidade. – Essa representação é função da navegabilidade e da multiplidade definidas para a associação, conforme visto mais adiante. 11 1
Especificação de classes de entidade Outro aspecto relevante para classes de entidade é modo como
podemos identificar cada um de seus objetos unicamente. – Isso porque, principalmente em sistemas de informação, objetos de entidade devem ser armazenados de modo persistente. – Por exemplo, um objeto da classe Aluno é unicamente identificado pelo valor de sua matrícula (um atributo do domínio). A manipulação dos diversos atributos identificadores possíveis em uma classes pode ser bastante trabalhosa. Para evitar isso, um identificador de implementação é criado, que não tem correspondente com atributo algum do domínio. – Possibilidade de manipular identificadores de maneira uniforme e eficiente. – Maior facilidade quando objetos devem ser mapeados para um SGBDR 11 2
Especificação de classes de controle Com relação às classes de controle, no projeto
devemos identificar a real utilidade das mesmas. – Em casos de uso simples (e.g., manutenção de dados), classes de controle não são realmente necessárias. Neste caso, classes de fronteira podem repassar os dados fornecidos pelos atores diretamente para as classes de entidade correspondentes. Entretanto, é comum a situação em que uma classe de controle de análise ser transformada em duas ou mais classes no nível de especificação. No refinamento de qualquer classe proveniente da análise, é possível a aplicação de padrões de projeto (design patterns) 11 3
Especificação de classes de controle Normalmente, cada classe de controle deve ser
particionada em duas ou mais outras classes para controlar diversos aspectos da solução. – Objetivo: de evitar a criação de uma única classe com baixa coesão e alto acoplamento. Alguns exemplos dos aspectos de uma aplicação cuja coordenação é de responsabilidade das classes de controle: – produção de valores para preenchimento de controles da interface gráfica, – autenticação de usuários, – controle de acesso a funcionalidades do sistema, etc.
11 4
Especificação de classes de controle Um tipo comum de controlador é o
controlador de
caso de uso, responsável pela coordenação da realização de um caso de uso. As seguintes responsabilidades são esperadas de um controlador de caso de uso: – Coordenar a realização de um caso de uso do sistema. – Servir como canal de comunicação entre objetos de fronteira
e objetos de entidade. – Se comunicar com outros controladores, quando necessário. – Mapear ações do usuário (ou atores de uma forma geral) para atualizações ou mensagens a serem enviadas a objetos de entidade. – Estar apto a manipular exceções provenientes das classes de entidades.
11 5
Especificação de classes de controle Em aplicações WEB, é comum a prática de utilizar outro tipo de
objeto controlador chamado front controller (FC). Um FC é um controlador responsável por receber todas as requisições de um cliente. O FC identifica qual o controlador (de caso de uso) adequado para processar a requisição, e a despacha para ele. Sendo assim, um FC é um ponto central de entrada para as funcionalidades do sistema. – Vantagem: mais fácil controlar a autenticação dos usuários. O FC é um dos padrões de projeto do catálogo J2EE – http://java.sun.com/blueprints/corej2eepatterns/Patterns/Fron tController.html
11 6
Especificação de outras classes Além do refinamento de classes preexistentes,
diversas outros aspectos demanda a identificação de novas classe durante o projeto. – Persistência de objetos – Distribuição e comunicação (e.g., RMI, CORBA, DCOM, WEB) – Autenticação/Autorização – Logging – Configurações – Threads – Classes para testes (Test Driven Development) – Uso de bibliotecas, componentes e frameworks Conclusão: a tarefa de identificação (reuso?) de classes não termina na análise.
11 7
Projeto de classes :
11 8