Dúvida sobre camada de serviço

Bom dia pessoas,

Estive lendo sobre classes de serviço, mas anda me ocorrendo uma dúvida a qual não consigo sanar, e vou me utilizar de um exemplo básico para vcs entenderem.

Um sistema básico para cadastro de clientes.

Eu terei uma classe Cliente:

[code]public class Cliente() {
private long id;
private String nome;
private String cpf;

//construtores, getters e setters

}[/code]

A classe ClienteDAO, responsável pela persistência.

Agora chegamos na classe ClienteService, onde reside minha dúvida:

[code]public class ClienteService {
private ClienteDAO dao = new ClienteDAO();

public void salvar(Cliente cliente) {
  if (!clienteDAO.isCPFCadastrado(cliente.getCPF())) {
    dao.salvar(cliente);
  }

}
}[/code]

Aí está o problema, o método retorna void, como minha classe controladora vai saber se o cadastro foi realizado ou não? Devo colocar boolean como retorno desse método? Como vcs fazem?

Se não fui muito claro em algo, é só falar.

Muito obrigado desde já e um grande abraço a todos!

Ninguém?

Eu coloco pro método no dao lancar HibernateException ou JDBCException e controlo as exceções.

Ideia muito boa! Mas repare que nesse caso não dá certo, já que se o cliente já for cadastrado, o controlador deve redirecionar pra mesma página com um aviso na tela, e se não for cadastrado, redirecionar pra tela de “cliente cadastrado com sucesso”.

Eu também li que as classes de serviço devem conter a lógica de negócio, e não ser apenas um delegate para as classes de domínio.

Como ficaria nesse caso?

Eu não gosto muito de trabalhar com retornos booleanos para caso de certo ou caso de errado, mas você pode fazer isso se quiser:

public booelan salvar(Cliente cliente) {  
 try{     
   if (!clienteDAO.isCPFCadastrado(cliente.getCPF())) {  
    dao.salvar(cliente);
  return true;
   } 
  return false;
 }catch(Exception e){
 return false;
} 

Eu prefiro criar minha própria exception:

public void salvar(Cliente cliente) throws CPFJaExisteException { if (!clienteDAO.isCPFCadastrado(cliente.getCPF())) { dao.salvar(cliente); } else{ throw new CPFJaExisteException(); } }

Mas aí tem que verificar padrão de projeto,se eu posso lancar a exception ali ou se tenho que controla-la, e isso já é com o chefe(ou não). :stuck_out_tongue:

Olá Boa tarde!

Prezados tenho feito desta forma

Classe de serviço

public class OcupacaoServiceImpl implements OcupacaoService, Serializable {

    private static final long serialVersionUID = -5527346777241342040L;
         
    @Inject
    private OcupacaoDao ocupacaoDao ;    
	
   @Transactional
   public void save(Ocupacao ocupacao) {
	ocupacaoDao.save(ocupacao);				
   }

Classe Controller

   public void gravar() {
        try {
	    this.ocupacaoService.save(ocupacao);
	    closeDialog();
	    displayInfoMessageToUser("Registro criado com sucesso!");
	    load();
	    preparaInclusao();						
	} catch (Exception e) {
            keepDialogOpen();
            displayErrorMessageToUser("Ocorreu um erro ao atualizar o registro");
            e.printStackTrace();
	}
}	

e como o ErickRAR demonstrou podemos fazer o que quizer na classe de serviço.

Estou fazendo exatamente isso. Mas acho que estamos pensando de forma diferente, quando vc diz “caso de certo ou caso de errado”, já que o cliente já estar cadastrado não implica nisso, e sim no domínio do sistema, sendo necessário estar no service ou na própria classe. Alias, nem o próprio boolean quer dizer “certo ou errado”, e sim “verdadeiro ou falso”.

Mas repare bem que, se eu deixar desta forma, fica estranho um método que apenas salva os dados no SGBD retornar true ou false no controller, assim como não posso deixar pra verificar se o cliente já é cadastrado no controller, pois teria regra domínio nele.

Eu poderia fazer assim:

[code]public class ClienteService {
private ClienteDAO dao = new ClienteDAO();

public void salvar(Cliente cliente) {  
  dao.salvar(cliente);  
}  

public boolean isCPFCadastrado(String cpf) {
  if (dao.isCPFCadastrado(cpf)) {
    return  true;
  }     else {
    return false;
  }      
}

} [/code]

E na classe controller:

[code]public class ClienteController {
@RequestMapping(value=“cliente/novo”)
public String cadastrar() {
ClienteService clienteService = new ClienteService;

String cpf = blablabla;
if (clienteService.isCPFCadastrado(cpf)) {
  clienteService.salvar;
  return "sucesso"; // redireciona pra página informando que o cadastro foi feito com sucesso
} else {
  return "cliente-ja-cadastrado"; // redireciona pra página informando que o cliente já possui cadastro
}

}
}[/code]

Mas desta forma eu estaria colocando regra de negócio - não poder cadastrar clientes de mesmo cpf no sistema - no controller. Tem horas que eu mesmo me pergunto se isso é realmente uma regra de negócio, visto que na maioria dos sistemas corporativos a inserção de dados redundantes - como dois registros de um mesmo cliente, nesse caso - é indesejado, o que o tornaria um interesse sistêmico - o que removeria ele da classe de serviço e poderia até ser tratado com AOP. O que vocês acham?

Sobre usar exceptions, eu vejo de forma diferente, já que elas não foram criadas pra isso. Colocar uma regra de negócio numa exception também não é correto, vc não acha?

Muito obrigado pela ajuda e atenção. Abraços!

rlira,

Não se trata de tratamento de erros, e sim de uma regra para impedir registros duplicados no banco de dados. Tenho que verificar, pelo cpf, se o cliente já está cadastrado ou não.

Mas como na tabela cliente o campo cpf é varchar, não pode ser PK. Desta forma, não posso deixar essa validação a cargo do banco, apenas capturando exceptions.

Muito obrigado pela atenção e ajuda. Abraços!

Outra alternativa seria:

public class ClienteService { public boolean isCPFCadastrado(Cliente cliente) { if (dao.isCPFCadastrado(cliente.getCPF())) { dao.salvar(Cliente); return true; } else { return false; } } }

E no controller:

public class ClienteController { @RequestMapping(value="cliente/novo") public String cadastrar() { if (clienteService.isCPFCadastrado(cliente.getCPF())) { return "cliente-ja-cadastrado" // redireciona pra página informando cliente já cadastrado } else { return "sucesso"; // redireciona pra página informando que o cliente foi salvo com sucesso } } }

O único problema dessa abordagem é que o controller não ficaria transparente, pois o método para salvar o cliente ficaria escondido na classe de serviço.

Up!

Algum moderador pode mover este tópico para “Arquitetura de Sistemas”?

Percebi que postei no lugar errado. Desculpe o incomodo.

Ninguem?

Não use um boolean para sinalizar se deu certo ou não, use uma Exception mesmo.

[quote=$ERVER]rlira,

Não se trata de tratamento de erros, e sim de uma regra para impedir registros duplicados no banco de dados. Tenho que verificar, pelo cpf, se o cliente já está cadastrado ou não.

Mas como na tabela cliente o campo cpf é varchar, não pode ser PK. Desta forma, não posso deixar essa validação a cargo do banco, apenas capturando exceptions.

Muito obrigado pela atenção e ajuda. Abraços![/quote]

Nesse caso eu faria o tratamento antes com uma exception (CPFJaCadastradoException) e também deixaria a coluna no banco como única, pois vai que uma hora passa e não percebo…

Não é bem colocar regra de negócio nas exceptions, é utiliza-la para melhorar o “caminho das pedras”. Capturando uma exception que já conheço, como por ex. CPFJaCadastradoException, já posso redirecionar o usuário para uma tela com lembrete de senha. Facilita bastante criar sua própria exception.

ErickRAR

Na verdade, o caso do cpf é apenas para ilustrar o problema. Na verdade o sistema é para controle de notas fiscais.

Duas notas com números iguais podem existir no sistema, desde que sejam de fornecedores diferentes. Ai já se trata de regra de negócio, entendeu?

E continuo afirmando, criar exceptions para regras de negócio é ERRADO!

Obrigado e abraços!

Ninguem?