Geração de Código
• Uma vez definidos os diagramas de colaboração e o diagrama de classes de projeto, a geração de código é uma tarefa passível de automatização.
• Trata-se aqui de gerar o código das classes
correspondentes à camada de domínio da aplicação, ou seja, as classes que realizam toda a lógica do sistema a partir das operações de sistema.
• As demais camadas (persistência, interface, etc.) são geradas em outra fase do processo.
• Pode-se admitir, porém, que, uma vez gerada a camada de domínio, todas as demais camadas serão derivadas e dependentes desta.
Classes
class Cliente {
};
Atributos
class Cliente {
private String nome; private Float debito; private Integer idade; }
Métodos para alterar e acessar
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; } }
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
Associações
•
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.
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)
Acesso aos elementos das
coleções
• Em relação aos métodos que consultam associações com multiplicidade *, observou-se nos diagramas de
colaboração que as mensagens de consulta do tipo
getClienteComNome eram enviadas à coleção em si.
• Porém, é indesejável implementar esta consulta desta maneira, pois visto que este método é específico da
coleção de clientes, seria necessário especializar a classe genérica com a estrutura de dados que representa a
coleção para cada um dos tipos de valor que ela pudesse conter.
• Assim, a aplicação teria classes como
ColecaoDeClientes, ColecaoDeFitas, ColecaoDeEmprestimos, etc.
• Essa abordagem é inconveniente pela proliferação de estruturas praticamente idênticas.
Como resolver este problema
•
Uma opção para evitar esse efeito indesejável é
implementar o método de consulta na classe
que está na origem da associação.
•
Assim, ao invés de implementar
getClienteComNome
em uma subclasse de
Colecao, implementa-se este método na classe
Videolocadora
visto esta estar na origem da
associação.
•
Desta forma, tanto associações quanto atributos
são consultados por métodos da classe
prefixados com get.
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.
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 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;
} }
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.
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;
} }
Associação Unidirecional para
*
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); }
Um método alternativo para
acesso
public Set getEmprestimosNaData(Date data) { private Set empND = new HashSet(); private Emprestimo atual;
Iterator inter = emprestimos.iterator(); while (inter.hasNext()) {
atual = (Emprestimo) inter.next(); if (atual.data().equals(data)) { empND.add(atual); }; }; return empND; }
class Videolocadora {
private List reservas = new ArrayList(); public Videolocadora() { }
public void adicionaReserva(Reserva reserva, int posicao) { this.reservas.add(posicao,reserva);
}
public void removeReserva(Reserva reserva) { this.reservas.remove(reserva);
}
public void removeReservaNaPosicao(int posicao) { this.reservas.remove(posicao);
}
public List getReservas() {
return Collections.unmodifiableList(reservas); }
public Reserva getReservaNaPosicao(int posicao) { return (Reserva) reservas.get(posicao);
} }
Associação
Unidirecional
<<ordered>>
class Videolocadora {
private Map cadastro = new HashMap(); public Videolocadora () { }
public void adicionaNoCadastro(Cliente cliente) { this.cadastro.put(cliente.getNome(), cliente); }
public void removeDoCadastro(Cliente cliente) {
this.removeDoCadastroPorNome(cliente.getNome()); }
public void removeDoCadastroPorNome(String nome) { this.cadastro.remove(nome);
}
public Collection getCadastro(){ return cadastro.values(); }
public Cliente getCliente(String nome) { return (Cliente) cadastro.get(nome); }
}
Associação
Unidirecional
Qualificada
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)
} }
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
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; }
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;
} }
Método Delegado
• Deve-se sempre observar o diagrama de colaboração onde ele apareceu.
• Toda mensagem com número x, que chega a uma instância da classe A deve ser implementada como a seqüência das
mensagens x.1, x.2, ..., x.n, que saem da instância de A e são enviadas a outros objetos.
Métodos Delegados e
Operações de Sistema
class Videolocadora {
private Cliente clienteCorrente;
private Map acervo = new HashMap();
public void emprestaFita(String codigoF) { private Fita f;
f = this.getFita(codigoF);
clienteCorrente.emprestaFita(f); }
class Cliente {
private Emprestimo emprestimoAberto; public void emprestaFita(Fita f) {
if (this.getEmprestimoAberto() == null) { this.criaNovoEmprestimo(); }; this.getEmprestimoAberto().criaNovoItem(f); } }
class Cliente {
private Emprestimo emprestimoAberto; public void criaNovoEmprestimo() {
private Emprestimo e = new Emprestimo(); this.associaEmprestimoAberto(e);
e.setData(Sistema.dataDeHoje()); e.setValorTotal(0);
} }
class Emprestimo {
private Set itensDeEmprestimo = new HashSet(); public void criaNovoItem(Fita f) {
ItemDeEmprestimo it = new ItemDeEmprestimo(f); this.associaItem(it);
this.setValorTotal(this.getValorTotal()+it.getValor()); }
class ItemDeEmprestimo {
private EstadoDeItemDeEmprestimo estado; public ItemDeEmprestimo(Fita f) {
EmAndamento estado = new EmAndamento(f); this.associaEstado(estado);
this.setPrazo(f.getFilme().getTipoDeFilme().getPrazo()); this.setValor(f.getFime().getTipoDeFilme().getValor()); }