geração de código. uma vez definidos os diagramas de colaboração e o diagrama de classes de...
TRANSCRIPT
Geração de Código
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 modificados.
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) Um método para obter objetos associados
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 estejam consistentes.
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 *
Corresponde à implementação de um conjunto
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; }
Associação Unidirecional <<ordered>>
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 Qualificada
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 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 criação/redefinição de associação
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());
} }
Até que ponto desenvolver os diagramas de colaboração? Desenvolver o diagrama até chegar às mensagens
básicas de criação e destruição de instâncias e de associações e de mudança de valor de atributo.
Essas mensagens básicas são normalmente terminais no diagrama de colaboração, sendo as mensagens intermediárias as mensagens delegadas.
Faz-se exceção, porém ao caso da operação de criação de instâncias que, conforme foi visto, pode implementar outras mensagens básicas à guisa de inicialização dos atributos e associações do objeto sendo criado.