Em um sistema tenho que garantir que um cliente nao pode ser salvo, cadastrado ou seja la como for sem que o seu nome e cpf sejam informadose estes sejam validos segundo regras.
Validar as regras do nome e do cpf podem ser feitas na minha propria classe de dominio na utilização dos sets por exemplo. Mas onde ficaria a regra que diz que ele tem obrigatoriamente que ter um nome e 1 cpf informado.
Bom nao sei se o exemplo e bom mas espero ter me feito entender.
1- Na minha classe Cpf eu somente colocaria um construtor com parâmetro, no caso número do cpf, caso o número do cpf passado como parâmetro fosse válido eu contruiria o objeto, caso contrário eu abortaria a contrução do objeto. Assim eu evito ter objetos Cpf inconsitentes, não seria muito legal eu poder criar objetos cpf com um numero inválido e depois fazer as verificação e ai sim descartar o objeto.
Agora sou eu que tenho uma dúvida será que tem como aborta a construção de um objeto? Lançando uma exceção?
2- No caso do cliente eu faria o mesmo que eu fiz com cpf. Não possibilitaria criar clientes sem nome, ou seja, objetos clientes inconsitente!
Se alguém puder comentar sobre a minha resposta, me ensinar ou dar uma idéia de como posso aborta uma construção de objeto.
Lançar uma exceção simplesmente faz o construtor “parar de executar” naquele ponto, mas o objeto já foi criado e a referência já foi guardada. A única maneira de “parar” a construção de um objeto é deixar a construção dele entro de um método que fabrique o objeto e teste as condições necessárias, aí o método chama o construtor ou não.
Dê uma olhada nos padrões de projeto Factory e Singleton.
[quote=Maurício Linhares]
Lançar uma exceção simplesmente faz o construtor “parar de executar” naquele ponto, mas o objeto já foi criado e a referência já foi guardada.[/quote]
Acho que não visualizei o que você disse
...
public class A {
public A() throws MyException {
throw new MyException("Error during instantiation");
}
}
...
Nenhuma referência para o objeto A será criada.
...
A a = null;
try {
a = new A();
} catch(MyException e) {
System.out.println("erro!");
}
System.out.println((a == null)?"nao criado":"criado");
...
Creio que o output do código acima sempre vai ser “não criado”. Então ninguém vai ter uma referência para uma instancia da classe A (apenas o garbage collector que vai ter que coletar o objeto que iria ser instanciado).
[quote=Maurício Linhares]A única maneira de “parar” a construção de um objeto é deixar a construção dele entro de um método que fabrique o objeto e teste as condições necessárias, aí o método chama o construtor ou não.
Dê uma olhada nos padrões de projeto Factory e Singleton.[/quote]
Singleton não se encaixa muito nesse proble pois ele te permite controlar uma única instancia. O que não é muito o caso do Cpf.
Factory ai sim é uma boa quando temos objetos composto, pois nesse caso a regras de negocio podem variar de uma aplicação para outra. É o caso de cliente. Em uma aplicação pode ser obrigatorio um cliente ter um cpf ai criamos uma factory para tratar isso nessa aplicação. Em uma outra aplicação pode NÃO ser obrigatorio um cliente ter um cpf mas é obrigatorio ter uma data de nascimento ai criamos uma factory para tratar isso nessa aplicação.
No caso de gerenciar a criação de Cliente realmente é bacana você colocar uma factory para fazer. Note que não é o mesmo caso de Cpf em qualquer aplicação não tem muito sentindo um objeto Cpf com um número inválido ou tem? Para mim Cpf possui regras invariaveis que fazem sentindo em qualquer aplicação, por isso não é muito legal eu usar uma factory para eu controlar essa regra de criação, pois sempre que eu for usar Cpf vou ter que usar a factory elas são classes altamente dependentes por isso devem estar juntos. Foi baseado nessa depeendencia que eeu levantei a questão do construtor.
Esse é meu ponto de vista… mas se alguem quiser comentar sobre ele sinta-se avontade…
[quote=Samuel_Pessorrusso]
Creio que o output do código acima sempre vai ser “não criado”. Então ninguém vai ter uma referência para uma instancia da classe A (apenas o garbage collector que vai ter que coletar o objeto que iria ser instanciado).
Abraços[/quote]
Muito bem visualizado por você samuel!
Quando exceção é lançada, todas as instruções após a exceção ser lançada vão ser ignoradas até que alguém trate a exceção. No caso um catch! Como a atribuição está após a exceção ser lançada, a atribuição será ignorada. Que seria o mesmo que não construir o objeto como visto pelo samuel!
Que burro eu sou por não ter visto isso erro de principiante! Ainda bem que eu sou principiante…
Mas ai samuel mandou bem em ter se atentado para isso…
Ja passei por esse problema, o que eu fiz foi criar uma interface ‘Avaliavel’, essa interface possui a assinatura de um método ‘validar’ que levanta uma exceção ‘AvaliavelException’, esta exceção possui uma lista de erros, um Collection por exemplo. Todo o objeto a ser salvo deve implementar essa interface.
O que eu fiz então foi que eu so poderia salvar objetos na minha base de dados do tipo ‘Avaliavel’, e antes de realmente salva-lo eu chamo seu método ‘validar’, no seu exemplo esse método deveria verificar se o ‘cpf’ existe e é válido, bem como o nome. Caso validar levante a exceção vc possui uma lista dentro de ‘AvaliavelException’ com todos os erros ocorridos.
Com isso vc atribui ao objeto do dominio que ele possa se validar. E sua classe que salva o objeto não precisa saber qual objeto se trata. Fica mais fácil inclusive vc incluir novos objetos de domínio na sua aplicação, basta que ele implemente a interface ‘Avaliavel’
Bom… e um caminho que eu nao tinha visualizado. O que eu nao queria era deixar esse trabalho para a camanda de controle pois pra cada dispositivo ( celular, desktop, web ) teria que duplicar tais validações.