DAOs, Repository, Service, Entity e Aggregate ! Como unir ou jogar fora tudo isso?

Ola
Tempos atrás eu tive algumas discussões aqui no fórum e isso me esclareceu algumas duvidas. Porem após dois meses ainda me falta compreender alguns assuntos.
Eu andei lendo alguns comentários aqui no fórum, e fiquei com algumas duvidas se estou aplicando corretamente DAOs, Repository, Service, Entity e Aggregate.

Eu tenho as seguintes situações, uma fabrica de Repositório que coleta o DAO correspondente através de IoC, segue código abaixo:

public abstract class RepositoryFactory {
	public abstract LoginRepository getLoginRepository();
	public static RepositoryFactory getRepositoryFactory(){
		Properties resource = Util.readResource();
		int whichRepository = Integer.parseInt(resource.getProperty("whichRepository"));	
		switch(whichRepository){
			case 1:
				return new HibernateRepositoryFactory();
			default:
				return null;
		}
	}
}

public class HibernateRepositoryFactory extends RepositoryFactory{
	private static final ApplicationContext context;
	static {
		try {
			context = new ClassPathXmlApplicationContext("iocForHibernate.xml");
		} catch (Throwable ex) {
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}
		
	public LoginRepository getLoginRepository() {
		return (LoginRepository) context.getBean("loginDAO");
	}
}

Eu não quero transpor a injeção de dependência para o Cliente, então faço uso de uma fabrica para abstrair isso, como demonstrei no código acima.
Portanto o Service do Usuário pode verificar se um determinado login existe no banco de dados da seguinte forma:

public class UserService {
	private static final LoginRepository loginRepository;
	static{
		RepositoryFactory factory = RepositoryFactory.getRepositoryFactory();
		loginRepository = factory.getLoginRepository();
	}
	
	public static boolean verifyLogin(Login login){
		List<Login> list = loginRepository.listByExample(login);
		if(list.size() > 0)
			return true;
		else
			return false;
	}
}

Feito isso eu tenho tudo preparado para o Cliente verificar se o login existe, da seguinte maneira:

public class LogonBean {
	public String verifyLogin(){
		Login user = new Login();
		user.setLogin(login);
		user.setPassword(password);
		boolean exist = UserService.verifyLogin(user);
		if(!exist)
			return "login_fail";
		else
			return "home";
	}	
}

Conclusão:
1)A injeção de dependência foi adicionado para que eu não precise ficar controlando as transações, como vc pode perceber eu não precisei ficar escrevendo begin transaction, rollback e etc.

2)A Fabrica serve para esconder do cliente a injeção de dependência.

3)O Service não fez muito sentido, pois o contexto aqui é muito pequeno, mas imagine uma situação de cadastro de usuário, nessa situação o Service poderia fazer uso de outros Repository, e novamente eu não quero transpor essa lógica para o cliente, portanto digamos que o Service contém parte da lógica.

4)A Entity esta espalhada por todos os cantos, uso esta dentro do Service para passar o critério de busca, uso ela também no Cliente para popular os dados que são coletados da interface web.

5)Creio que esteja faltando o Aggregate, dessa forma não teríamos a Entity trafegando entre as camadas, mas eu particularmente acho muito trabalhoso ficar criando esses Aggregate e estes não me traz muitos benefícios.

6)Eu estou pensando em juntar o Entity com o Service, mas usando IoC para isso, assim o nosso Cliente poderia usar algo semelhante ao ActiveRecord dentro da Entity

7)Apesar de adicionar essas implementações eu ainda acho que estou caindo no problema do Modelo Anemico, e que ainda preciso me aprofundar mais nos conceitos de DDD. O DDD me ajudou mais na forma de conceber o projeto do que no código em sí. Aprendemos a não usar Waterfall, criamos uma linguagem comum de comunicação com os clientes, procuramos definir quem são os Peritos do Domínio e etc, porem acho que no código em si eu não evolui muito e percebi que os problemas de software estavam mais relacionados na concepção do projeto do que código fonte do projeto.

Quem são as suas entidades ? Usuário, Login ou ambas ?
O que Login é de Usuário ?

Não existe [LogicadeAcessoADados]Repository e sim [Entidade]Repository
Seu sistema deve ter UsuarioRepository, ClienteRepository, PedidoReposity e não HibernateRepository.
(A menos, é claro, que Hibernate seja o nome de uma entidade … )
Por outro lado não deve ter [Entidade]DAO e sim [LogicadeAcessoADados]DAO. Ou seja, deve ter HibernateDAO
e XMLDAO. ou DistribuidoComCacheDAO, ou JDBCDAO.

DAO são plugáveis, logo têm Factories e são injetados em outros objetos.
Repositorios não são plugáveis e não são obtidos de factories. Eles contém factories e as usam para
realizar seu trabalho, mas seu trabalho é único , ele é vinculado ao sistema , à logica de negocio.
Se a logica de negocio muda , a logica do repositorio muda , assim como a das entidades.
VC não irá nunca mais usar a logica anterior (*)

Reflita nestas questões para entender o que está errado no seu modelo DDD.

  • Num desenvolvimento sadio e competente é claro. Se foi tomada uma decisão na empresa para impor a regra de negocio X espera-se que não se arrependam. Se isso for um problema podemos ainda criar estratégias de negocio dentro dos repositorios, mas isso é overkill para um ambiente normal de desenvolvimento. Por outro lados existem os CVS da vida para recuparar o código antigo se for realmente necessário.

Ronildo,

a resposta para sua pergunta é bastante complexa para ser dada em um fórum, mas (acredite!!!) existe um jeito simples de usar MDD com Hibernate.

Abraço.

[quote=sergiotaborda]Quem são as suas entidades ? Usuário, Login ou ambas ?
O que Login é de Usuário ?
Reflita nestas questões para entender o que está errado no seu modelo DDD.
[/quote]

Tudo bem, vou tentar me expressar melhor.
Uma entidade é uma abstraçao do mundo real, que quarda informaçoes de um determinado elemento. O conjunto de entidades pode representar uma tabela no banco de dados.

Para manipular essas entidades nos precisamos criar serviços responsáveis para esta tarefa. Saindo um pouco da informática vou tentar expressar essas idéias em algo mais simples que eu vejo no meu café de manhã.

Imagino o pão frances como uma entidade, o qual possui informações sobre as caracteristicas do mesmo. Para obter 10 pães eu faço uma requisição ao atendente da padaria, este por sua vez procura os pães dentro de uma cesta de pães e me retorna o pedido.

Creio que o exemplo acima seja um dominio, e vou tentar abstrair este problema do mundo real para uma possivel solução dentro da informatica, portanto segue solução abaixo.

O pão é uma entidade, eu sou o cliente ou servlet, o atendente é o serviço, e a cesta de pães é o repositorio. Eu poderia especificar varios repositorios diferentes, pois uma padaria faz diversos tipos de pães, assim o atendente (Servico) pode retornar diferentes tipos de pães, pois ele tem a sua disposição diferentes repositórios.

Se isto estiver correto com as regras do DDD, eu nao vejo muita diferença sobre o modelo anemico. O modelo anemico citado por Martin Fowler diz que as entidades nao podem ser separadas da logica, portanto como fazer isso no exemplo da padaria ?

Ronildo, a pergunta não era retórica. Quais são as suas entidades ?

Login é a minha entidade

Login é a minha entidade[/quote]

Se Login é a sua entidade qual é a Identidade dele ?

E Usuário , não é uma entidade ? Não existe no seu sistema. Se existe, qual é a relação dele com Login?

Estou ressucitando este tópico, porque tive um problema semelhante, e resolvi da seguinte forma:

[code]public class Usuario {
// A identidade aqui é o login
private String login, senha;

public Usuario(String login, String senha) {
    this.login = login;
    this.senha = senha;
}

// getLogin(), setLogin(), setSenha()

}[/code]

[code]public class LoginService {
private UsuarioRepositorio repositorio;

// Injetando o repositório
public LoginService(UsuarioRepositorio repositorio) {
    this.repositorio = repositorio;
}

public Usuario login(String login, String senha) {
    Usuario u = repositorio.getByLogin(login);

    if (!u.getSenha().equals(senha)) {
        throw new UsuarioInvalidoException("Usuário inexistente ou senha inválida.");
    }

    return u;
}

}[/code]
Ou seja, login seria um service, e não uma entidade.
Estaria correto isso? Ou a classe Usuario deve ficar responsável pelo controle de acesso?
Abraços

Olá,

A maneira que você fez me parece uma boa.
O objeto usuário não deve saber se autenticar pois autenticação é tarefa de infra, então neste caso o service é uma boa solução.

Se você quiser explicitar no seu modelo de dominio que o usúario loga, então você poderia ter o método logar() na entidade usuario, e esse método delegaria a tarefa para o service (ainda assim o servico continua fazendo o controle de acesso).

[]s
Ferry

Não gostei muito do HibernateRepository porque dá a impressão que o conceito de repository não foi compreendido.
O repository não deve existir se ele não existir na situação de negócio.

Pra falar a verdade acho que você tentou usar o DDD como um template de arquitetura e isso não dá muito certo, pois DDD é um processo que tem requisitos de aderência e deve ser aplicado em concordância com a equipe e com presença dos domain experts.

[editado: propaganda nao, obrigado]

Grande Abraço,

Esqueci de quotar, meu comentário foi em relação ao post do tnaires.

[]s