[quote=sergiotaborda]Para você ser marceneiro você tem que saber o que é madeira. Para vc trabalhar com OO, vc tem que saber SoC.
Senão vc não está fazendo OO. Este é o ponto.
Sim, muita gente tem duvidas quanto a SoC. Mas esse é o tipo de coisa difícil de explicar no forum. Vamos então com algumas coisas básicas.
O que é o básico do SoC ? Cada classe deve ter o minimo de responsabilidade possivel, mas não menos.
Se eu cozinho sou cozinheiro, se vendo, vendedor, se como, comilão
se choro, chorão … se valido ?
Validador!!!
Validações são feitas por validadores! Não por serviços. Não por entidades. Não por DAO, não por nada que não tenha a única e exclusiva responsabilidade de validar.
isSenhaValida é um caso para um validador de senha. “Senha” , pasmem-se, é uma entidade. Ela só não é um agregado.
Então aqui já temos : Senha e Validador
Mudar se senha… humm… mudar de senha é um assunto delicado. O que acontece se algum passo der errado ?
hummm… isso soa a transação… é! transação. E transação é coisa para serviços.
Usuários têm senhas, não são senhas. Senhas não são atributos do usuário, são associadas a usuários. ( um atributo é associado, mas algo associado, não é necessariamente um atributo)
Um usuário pode ter mais do que uma senha conforme o que a senha protege. É para isso que existe o single sign on (uma senha to rule them all => existe mais que uma).
Usuário.temPermissão(paraLevarTodoOdinheiroDoBancoParaCasa) ? O que vc acha que ele irá responder ?
Verificação de permissões é feita por um agente de segurança ( um Guardian), não pelo o usuário. O modelo é o seguinte: o sistema tem que ser protegido. Para isso existem agentes de segurança que autenticam e autorizam (ou não) o usuário. Vários agentes, várias permissões, um usuário.
Em um banco, A compra ações de B. Quem faz a transação ? o Broker. Quando existe um terceiro cara isso significa : serviço. (Serviço de Broker , ou Broking. Já ouviu falar?)
Qual é a responsabilidade de um entidade ? Ter identidade. São simples quanto isso. Para isso ela tem que ser criada. Aqui que complica. Manter o estado do objeto é simples (get/set) mas e manter o estado do sistema ? posso dar set em qualquer objeto a qualquer hora ? Não. Isso é delicado. É coisa para alguem responsável. Mais responsável que a entidade : o serviço.
Quem pinta é pintor, quem constrói é … ?
Construtor.
O padrão Builder é para criar objetos ( entidade é um caso particular de objeto) com estado consistente quando usar set não é atómico o suficiente ( ou seja, vc precisaria setar duas ou mais coisas simultaneamente e isso , simplesmente, é impossível com set)
Métodos “set” são Modificadores. Isso significa que estão mudando algo. Isso significa que eles não criam nada, apenas alteram. Para criar é preciso usar construtores ou outros objetos como Builder.
(é por isso que injeção via método set é furada na certa. só viável em caso em que a dependência é opcional.)
produto.alteraQuantidadeEstoque ( 20) … hummm… e quando o produto está em rota dentro de um caminhão. O que esse método faz ? manda um sms para o armazém ?
Produto tem um estoque ? Não. Estoque tem produtos.
Estoque.alteraQuantidade(Produto, 20) seria melhor. Melhor ainda :
Quantidade<Produto> quantidadeTransferida1 = estoqueA.remove(produto, 20);
estoqueB.adiciona(quantidadeTransferida1);
Transferencia transferencia1 = Transferencia.nova(estoqueA, estoqueB, quantidadeTransferida1 , relogio.agora());
Logger.log(transferencia1);
//diferente de:
Quantidade<Produto> quantidadeTransferida2 = estoqueB.remove(produto, 20);
estoqueA.adiciona(quantidadeTransferida2);
Transferencia transferencia2 = Transferencia.nova(estoqueB, estoqueA, quantidadeTransferida2 , relogio.agora());
Logger.log(transferencia2);
ups…enganei-me
Transferencia estorno = transferencia2.reverse(); // transferencias sabem como seria a sua "anti-transferencia. isto é um método que não altera dados, cria outra coisa, mas não precisa ser transacional.
Logger.log(estorno);
Quantidade<Produto> quantidadeTransferida3 = estoqueB.remove(produto, 40);
estoqueA.adiciona(quantidadeTransferida3);
Transferencia correto = Transferencia.nova(estoqueB, estoqueA, quantidadeTransferida3 , relogio.agora());
Logger.log(correto );
O assunto é vasto e complexo. Isto é só uma base.
Ah! e Validação é feita por Validadores. Objetos são responsáveis pela sua Consistência.
Validação != Consistência.
[/quote]
Muito interessante seu post, me deu novas idéias. Aproveitando o assunto SoC, minha dificuldade é separar as responsabilidades entre:
Action
Service
Entity
Tipo como uso JSF, e meus atributos são injetados diretamente logo apos o submit, já no seu estado consistente, visto que uso Validadores e Converters do proprio JSF , minhas Action acaba como sendo uma ApplicationLayer, ai pergunto deste modo seria responsabilidade da Action realizar pesquisas, entre outras coisas recuperar o usuario que esta logado, e deixar pro services as inserções e alteracoes no sistema?
E o service seria o responsavel por abrir fechar e commitar transacoes, seria feito da forma mais monotona mesmo, tipo:
FuncionarioService(){
public void createFuncionario(Funcionario f)throw SaveException{
Repository<Funcionario> funcionarioRepository=new RepositoryFactory().getFuncionarioRepostiory();
funcionarioRepository.getSession.beginTransaction();
try{
repositorio.add(f);
repositorio.getSession.getTransaction().commit();
}catch(Exception e){
repositorio.getSession().getTransaction.rollback();
throw new SaveException(e,"Erro ao salvar o Funcionario");
}
}
Seria responsabilidade do Service, abir, commitar, e fechar transacoes. Pois desta forma, eu consigo ter total controle do codigo, e da atomicidade das transacoes. O unico problema e que o codigo se torna repetitivo, e chato.
E por ultimo as entity ficariam responsaveis somente por consistencias do tipo:
Funcionario
private int idade;
setIdade(){
if(idade <0)
throw new IllegalArgumentException("Idade ilegal");
}
}
}
Neste contexto, se eu nao usar nenhum container de IOc, ou J2EE de controle de transacoes, onde ficariam as mesmas?
Obrigado!