Injeção de Dependência em Domain Model (ServiceLayer+DomainModel+Repository)

… o DAO esta desacoplado.

Prefira composição a herança:

http://javaboutique.internet.com/tutorials/Inherit_Compose/


Prefira composição a herança:

http://javaboutique.internet.com/tutorials/Inherit_Compose/



[/quote]

Eu não concordo que isso se aplique aqui, mas se vc tem uma ideia de como composição pode resolver o problema do reaproveitamento de codigo que o BiraBoy explicou, venha ela …

… composição resolve neste caso, conforme descrevi a uns 4 posts acima.

???

Usar Strategy não é composição, é Strategy. Ter um objeto DAO injetado não resolve o problema exposto que é : não reimplementar funcções simples de CRUD para cada Repository. Então vc faria

abstract class Repository {
 
    protected DAO dao = DAOFactory.getDAO();


    public void store (Object obj){
         dao.save(obj);
    }

    public void remove(Object obj){
         dao.delete(obj);
    }

}

//e depois 

class ClientRepository extends Repository {

         public List<Client> clientesComPagamentoEmAtrazo(Date date){
                   // monta uma query e envia ao dao
                   // o dao é o mesmo que no pai. 
                   return dao.list (Client.class,query);
         }

       // não é necessário implementar nem remove, nem save, nem nada que já exista no Repository  pai.
}

Como ClientRepository poderia reaproveitar o codigo de repository sem herança ?
Bom poderia ser assim (com composição)

[code]
Repository é uma interface

class GenericRepository implements Repository {

 private DAO dao = DAOFactory.getDAO();  

     public <T> List<T> list(Class<T> c , Query query ){
             return dao.list(c,query);
     }

public void store (Object obj){
dao.save(obj);
}

public void remove(Object obj){
     dao.delete(obj);
}

}

class ClientRepository implements Repository {

     private final Repository generico = new GenericRepository();

     public List<Client> clientesComPagamentoEmAtrazo(Date date){
               // monta uma query e envia ao dao
               // o dao é o mesmo que no pai. 
               return generico.list(Client.class,query);
     }

  // repetição dos métodos da interfac Repository, que é exactemtne

// o que não se quer fazer
public void store (Object obj){
generico.store (obj);
}

public void remove(Object obj){
     generico.remove(obj);
}

}[/code]

Qual é a vantagem ? Herança não é mais simples ?
Afinal ClientRepository É-UM Repository e mais do que isso ele SÓ-PODE-SER-UM reposiotry, que é a condição para que Repository seja uma classe abstract e ClientRepository a herde. Se Repository é uma interface eu poderia fazer

que não faz nenhum sentido. Então, não vejo como composição se encaixe melhor do que herança.

[quote=BiraBoy]É verdade. No meu caso, como estou acostumado a utilizar um DAO genérico com hibernate e somente criar DAO’s específicos quando desejo uma consulta mais específica, estou pensando como se daria para as interfaces de Repositório do DomainModel serem implementadas pelo DAO genérico (ao menos nas funcionalidades que equivalem a CRUD) e só serem implementadas por DAO’s específicos em caso de consultas específicas.

Como poderia fazer isso?[/quote]

Eu tb uso DAOs genéricos, do jeito que os caras da Hibernate recomendam. Quando preciso de uma consulta mais específica, eu coloco no ObjetoDeDominioDAO (que extende a GenericDAO).

Nunca precisei usar Repositories (pelo menos classes com o nome ObjetoDeDominioRepository) e consigo ter um modelo arquitetural bastante enxuto com o uso dos recursos do Hibernate.

Sergio, não é um erro você utilizar herança caso o controle do código esta em sua mão. O perigo é quando você tem uma grande equipe e decide usar componentes com base em sua implementação e o resto do desenvolvimento necessita herdar de seu componente sem a garantia que a implementação dos métodos ganhos lhe satisfazem

O repositório é específico da regra do domínio, assim como sua persistência.
Não existe garantia que o RepositórioUsuario utilize o mesmo DAO para persistência que o RepositórioFornecedor (isso pq sabemos da famosa afirmação, Repository é negócio, DAO é serviço de persistência). Ao afirmar que os DAOs podem ser diferentes, não apenas afirmo que um pode usar JDBC e outro JPA, mas principalmente que um pode persistir no Servidor X Oracle e outro no servidor Y MySql. Herdar a forma de que um repositório faz acesso a dados é engessar a abstração Repository (a não ser que você tenha garantias da forma de persitencia, incluindo a localização física).

Então alguém pode dizer: “Simples, sobreescrevo o método CRUD se necessário”. Se pensar assim, você tem conhecimento dos detalhes da implementação da classe pai (caso contrário você não teria métrica para tomar tal decisão). Obrigar este tipo de conhecimento, é justamente o que condena os links que postei.

Outra situação é de que um userRepository.store() pode fazer muitas outras coisas do que simplesmente invocar um dao.save. Aqui tbm poderia ser dado overhide e depois invocado um super.store, contudo qual é a garantia que o método store do “pai” não anule as alterações do filho?

No exemplo que você postou, eu não utilizo "Repository generico = new GenericRepository(); " nos Repositories como objeto composto, e sim a interface DAO como atributo. Isso permite que injete diferentes DAOs dependendo que Repository estou e garanta a forma como vou acessar os dados.

E como eu não posso utilizar de composição + interface para implementar Strategy?

Utilizo Strategy para resolver meu acesso a dados do repository. O repositorio não sabe como fazer isso, quem sabe é seu atributo DAO (que é a interface “estratégica”).

Ah, claro, lembre-se tbm que você não deve ter um repository para cada Entidade, e sim apenas para Agreggate roots. Sendo assim o repositório tem que fazer CRUD tbm nos agregados. Neste caso a herança tbm não ajudaria.

Quando eu mencionei que tinha respondido em 4 mensagens anteriores, com o uso de composição, não queria dizer que escrevi algo genérico, pq em minha opinião isso não casa com tudo que estamos discutindo com o que o Repository deve prover. Apenas descrevi a maneira de desacoplar o dao do repository.

[quote=Lezinho]Olá Rodrigo …

Agora uma Service, é um padrão que encapsula seu Domain MOdel. Ele antecede as Entidades e controla o fluxo das execuções. O comportamento da entidade (seus métodos de negócio) possui lógica, um service apenas opera como uma fachada. Sendo assim, uma entidade não deve invocar um service, e sim ser invocada por um.

[/quote]

Lezinho, não confunda o Service Layer do Fowler com o Service do Evans. É uma confusão bem comum. O Service do Evans é um elemento do domínio que encapsula comportamentos que você não consegue alocar naturalmente a um entity. O Evans chama Service Layer de Application Layer (não sei porque esses caras são tão amigos e não usam a mesma terminologia). Service != Façade.

Eu injeto Services nos Entities para encapsular processamentos complexos ou que podem variar (Strategy).

[quote=Lezinho]Sergio, não é um erro você utilizar herança caso o controle do código esta em sua mão. O perigo é quando você tem uma grande equipe e decide usar componentes com base em sua implementação e o resto do desenvolvimento necessita herdar de seu componente sem a garantia que a implementação dos métodos ganhos lhe satisfazem
[/quote]

Isso pode até ser verdade. Mas se tivesse medo disso não usaria as classes abstractas do java.
Ou as classes abstractas são bem implementadas ou não são. Cabe a quem as faz prover que sejam boas.

O que eu não entendi é o codigo que vc propõe que se use se não quisermos usar herança. Vamos pensar por um momento que é proibido usar herança. Então, como é que, com composição, resolveriamos o problema proposto de não reescrever métodos CRUD simples? Ou vc acha que tais métodos não existem ? Que todos os métodos do Repositorio são complexos por tratarem de agregados ? Vc mesmo me lembrou que nem todos os entitty são agregados complexos…

Parece que é ha uma dicotomia: por um lado vc aceita que existem entities simples o suficiente que não precisam de repository. Por outro vc aceita que o cliente de um dao deve sempre ser um repository.
Ora, se para comunica com o dao preciso sempre de um repository, então preciso de um mesmo quando o codigo é simples o suficiente para ser igual para todas as entidades. Não ?
Agora vc me diz que nem todas as entities tem repository… bem, vc tem que escolher. Afinal como é?

Tudo bem que vc pode querer dao de locais fisicos diferentes, mas ai vc simplesmente parametiza a fabrica.
Nada disso impede que o algoritmo que procura e seta o dao do repositorio seja comum a todos os repositorios. Tb nada impede que existam métodos simples no repositorio que eu herde e reimplemente quando precisar.

Se formos levar esta arquitectura às ultimas consequencias rápidamente vc descobre que vc vai precisar de um registro de repositorios, porque essa é a forma correta de declarar os repositorios de forma independente do codigo que os usa (mesmo quando o registro for implicito). No outro extremo vc vai descobrir que se usar um dao do tipo hibernate e todas as entidades forem simples, então vc vai precisar de apenas 1 repositorio generico que delega tudo para 1 dao. E isso automática transforma o " 1 repositorio + 1 dao hibernate " num anti-pattern.

Eu só tentei apresentar um solução para o colega de como reaproveitar os métodos. Vc levantou a questão de usar composição em vez de herança. Como é que composição resolve o problema de não ter que reescrever os métodos ? Foi isso que não entendi.

Eu até entendi que “composição” se referia a usar os DAO/Strategy , mas não entendo o que isso tem a haver com herança da classe repositorio.

Não é necessáriamente verdade. Desde que a super classe esteja bem documentada é perfeitamente natural usá-la. Vai-me dizer que nunca usou AbstractAction do swing ? ou AbstractTableModel ? Então! classes abstractas são boas. Acho que é bastante simples um contrato que usa um default e vc é livre de redefinir o default quando quiser. E reimplementar store() parece-me bastante intuitivo se vc quiser alterar o algoritmo que guarda o objeto.
Agora vc vai argumentar que o DAO é uma coisa interna do repositorio e portanto teria que saber que o repositorio tem um dao para que ao reimplementar store() o possa usar. Ora, isso é bem simples de conseguir. Faça o dao ser privado e crie um metodo protegido para o acessar. Desta forma classes da hierarquia têm toda a informação que precisam e classes clientes nem sonham que existe um dao.
Enfim, se vc quiser fazer bem feito e sem esse temor sobre como o próximo vai reimplementar sua classe abstrata, ha como fazer.

Vc está partindo do pressuposto errado de que se chamaria super.store(). Se o seu objetivo é redefinir o algoritmo, não ha porque usar o algoritmo velho dentro do novo. Não faz sentido, até porque vc não sabe qual era o velho.

Eu sei. Eu entendi isso. O que não consigo ver é onde isso substitui herança.
(veja que usei o DAO dentro do GenericRepository)

[/quote]

Releia os links que passou antes. O dilema não é entre herdar ou compor. O dilema é saber usar as diretivas É-UM e TEM-UM corretamente. Quando vc usa strategy, vc claramente sabe que a classe não é-uma estratégia, a classe tem-uma estratégia (de entre várias posssiveis). Foi isso que quiz dizer com “strategy não composição” referindo-me ao facto de ao vc usar DAO como estratégia não está escolhendo entre se o repositorio É-UM DAO ou ele TEM-UM DAO. Vc já escolheu que ele TEM-UM DAO ao escolher o padrão Strategy. Agora, isso, não tem nada a haver com eu poder ou não extender o repositorio. Por isso que eu sigo sem entender o isto tem a ver com herança. Se houve alguma duvida quanto a se um repositorio é-um dao eu entenderia o seu comentário, mas não é o caso. O que estava em causa era os vários tipos de repositorio compatilharem codigo. A composição não é um meio deles fazerem isso… pelos menos não a composição de DAO/Strategy.

[quote=Domain Driven Design Quickly]A service is not about the object performing
the service, but is related to the objects the operations are
performed on/for. In this manner, a Service usually becomes a
point of connection for many objects
.[/quote]

rodrigoy, como você pode ver na citação acima, um service do DDD é um ponto de conexão de vários outros objetos, afim de fornecer uma determinada operação. Muita semelhança com o padrão descrito por Fowler, não concorda?

Quanto a nele conter os objetos de domínio ou os objetos de domínio conter eles:

A execução da operação do Service é referenciada para outros objetos no domínio.

[quote=Lezinho]

A execução da operação do Service é referenciada para outros objetos no domínio.[/quote]

A tradução correta seria:

“A execução da operação do Service refere-se a/aponta para/depende de outros objetos no domínio.”

[quote=sergiotaborda]Isso pode até ser verdade. Mas se tivesse medo disso não usaria as classes abstractas do java.
Ou as classes abstractas são bem implementadas ou não são. Cabe a quem as faz prover que sejam boas. [/quote]

A questão não é ser classe abstrata, e sim as funcionalidades herdadas e seu uso. A própria classe Repository do seu pseudo-código não tem característica de classe abstrata, é uma classe convencional, que não exige nenhum método a ser implementado pela classe filha.

É válido uso de classes abstratas quando seus filhos assumem como “seus”, os métodos implementados do pai, apenas especializando os métodos abstratos que justificam a existencia de "N"classes filhas. As classes filhas não sobreescrevem os métodos do pai, pois pela modelagem é assumida tal coesão.

No seu exemplo não existe tais métodos abstratos logo não se justifica a herança de classe abstrata. As operações de CRUD nos repositórios não recebem necessariamente o mesmo tratamento (não existe conceituamente esta garantia) , logo isso tbm desmotiva o uso da Herança para os repositórios.

Parece intuitivo pra você que criou o método. E se o store da classe pai escreve em log a operação e dispara um email além de persistir? Você acabou de perder funcionalidades. Herdar e sobreescrever quebra o encapsulamento, pois você tem que conhecer os detalhes da implementação do pai.

Para evitar herança se usa composição (quando a herança não se qualifica como um subtipo). Herança não serve para deixar de digitar código, serve para qualificar um subtipo. Não existe um objeto de negócio “Repository” com CRUDs na definição de negócio, e sim CustomerRepository, ProductRepository e etc, isso é, a não ser que de fato Repository fosse abstrata, mas como você definiu, ela é concreta, pelo menos lógicamente. Portanto não faz sentido o ancestral em comum, tbm não faz sentido tais subtipos, pelo menos para os motivos expostos.

Contudo o q sugeri foi simplesmente desacoplar o DAO, não foi fazer “A Repository Genérica”, mesmo em CRUD. Como venho dizendo não vejo sentido nisso.

Quem disse que não são todas as entidades que precisam de repositories não sou eu, é a literatura:

[quote=Domain Driven design Q.]Provide
repositories only for Aggregate roots (…)[/quote]

Os agregados que não possuem Repositories são reportados ao Repository da Entity root do Agreggate. Tal repositório é cliente de um DAO, simples assim. Nesta caso o “benefício” da herança do CRUD pode não ser utilizado.

Nunca disse que todos os métodos são agregados ou que todos são complexos. Mas só por saber que vão existir agregados e vão existir CRUDs que não vão simplesmente chamar um DAO diretamente (o negócio possibilita isso), ja me faz crer que o possível ancestral comum seria apenas por conveniência e não por um bom Design, e isso não me agrada.

Pelo contrário, pra mim quem tinha que ter o DAO é o MinhaClasseRepository, pois OutraClasseRepository pode ter um DAO diferente… Uma classe “genérica” com a implementação do DAO toda sua não acho uma boa sugestão. No mínimo isso deveria ser setado pelos filhos, para quem quer utilizar este tipo de arquitetura …

Claro que pode fazer sentido. Você pode apenas somar uma regra, como disparar uma thread de geração de relatório, e continuar com a outra definição do super.store. Mas a questão é se isso seria uma boa idéia. Eu acho que não, mas tem gente que faz (principalmente se usou a herança só por conveniencia).

[quote=sergiotaborda]
Se formos levar esta arquitectura às ultimas consequencias rápidamente vc descobre que vc vai precisar de um registro de repositorios, porque essa é a forma correta de declarar os repositorios de forma independente do codigo que os usa (mesmo quando o registro for implicito).[/quote]

Que exagero… eu só usaria Regyster se hoje em dia ainda não existisse tantos frameworks com D.I.P.

Estamos de fato discutindo coisas diferente. Meus posts foram em relação a pergunta “Como desacoplar o DAO?”. Justamente pq acho uma péssima idéia os Repositórios compartilharem CRUD… (ja disse, operações do repositório são operações de negócio, não existe garantia que todos os CRUDs deverão ter o mesmo comportamento de negócio).

Mas tá, nada disso é regra e ninguém vai chegar a lugar algum, gosto é gosto. Particularmente, eu não aprovo Herança por conveniência, não acho uma boa prática.

Apenas transcrevi a idéia … no caso use então:
A execução da operação do Service aponta para outros objetos no domínio(…) dá na mesma.
Em DDD Service continua sendo um workflow para os objetos de negócio.

[quote=Lezinho][quote=Domain Driven Design Quickly]A service is not about the object performing
the service, but is related to the objects the operations are
performed on/for. In this manner, a Service usually becomes a
point of connection for many objects
.[/quote]

rodrigoy, como você pode ver na citação acima, um service do DDD é um ponto de conexão de vários outros objetos, afim de fornecer uma determinada operação. Muita semelhança com o padrão descrito por Fowler, não concorda?

Quanto a nele conter os objetos de domínio ou os objetos de domínio conter eles:

A execução da operação do Service é referenciada para outros objetos no domínio.[/quote]

O que Fowler descreve não é um padrão, mas uma camada… No DDD, services são conceitos do domínio, assim como repositórios e entities.

Services Layer (também conhecido como Application Layer) não deve ter regras de negócio (apesar de que do ponto de vista do cliente é indiferente). O papel do services como camada é a coordenação de fluxos e responder às solicitações, eventualmente entrando na camada de domínio.

Ou seja, de semelhante só tem o nome… Por isso prefiro o termo Application Layer.

Se não é um padrão, então tente dizer isso a Randy Sttaford, que descreve no POAA a literal diferença entre o “PATTERN” Session Façade e o “PATTERN” Service Layer, exatamente com estas palavras. Neste mesmo capítulo é mencionada a Application Layer, tendo como a ServiceLayer uma ponte entre esta (AppLayer) e a modelo de domínio.

O Domain Driven Design diz que:
“A Service usually becomes a point of connection for many objects”
… exatamente como um objeto da ServiceLayer, onde que não tendo lógica de negócio, delega essa aos objetos do domínio.

Se não é um padrão, então tente dizer isso a Randy Sttaford, que descreve a no POAA a literal diferença entre o “PATTERN” Session Façade e o “PATTERN” Service Layer, exatamente com estas palavras. Neste mesmo capítulo é mencionada a Application Layer, tendo como a ServiceLayer a ponte entre esta e a modelo de domínio.[/quote]

Você quer dizer então que Application Layer é a Client Layer? Sério, não entendo sua interpretação de Application Layer.

No link da minha resposta anterior tem uma citação desse cara sobre Services Layer: “Defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation.”

[quote=Lezinho]O Domain Driven Design diz que:
“A Service usually becomes a point of connection for many objects”
… exatamente como um objeto da ServiceLayer, onde que não tendo lógica de negócio, delega essa aos objetos do domínio.[/quote]

Uma definição mais clara seria: Um Service (DDD) é um ponto de conexão para vários objetos (de domínio) que compartilham de uma mesma regra de negócio. Observe que não saímos do domain layer aqui.

A diferença fica evidente se dissermos que um Service (DDD) poderia ser chamado da Service/Applcation Layer, mas o contrário não deveria ser permitido se você considerar uma premissa básica da separação em camadas: Dependência apenas de camadas abaixo.

Services e Repositorios pertecem ao domínio
Service/Application Layer NÃO pertece ao domínio (apesar de fazer uso do mesmo)

“Client Layer”?

Client Layer é qualquer camada que faça uso de outra camada, ou seja, uma camada cliente da outra… isto sim não é Padrão. Praticamente todos diagramas DDD envolve "Client"s que representam tais camadas.

Um repositório pode ser client de um DAo, uma Entity pode ser cliente de um VO, um Aggregate pode ser client de um Entity …

“Camada de aplicação” é aquela relevante ao contexto da aplicação (ManagedBeans, Actions) ou aquelas que server como uma Supercamada para a de Serviços, oferecendo suporte como de email, ftp, etc (de nada tem haver com o negócio).
No livro de Fowler você vê Service direcionados ao negócio, que faz o workflow aos entities e VOs, e aqueles definidos como seu supertipo para suporte a serviços da aplicação.

Na própia citação que você coloca, é definido o Service como uma fronteira entre a aplicação e o Domínio.

No DDD isso não muda, podendo existir tanto Service voltado a negócio como para Aplicação:

[quote=Domain Driven Design]“While using Services, is important to keep the domain layer
isolated. It is easy to get confused between services which
belong to the domain layer, and those belonging to the
infrastructure. There can also be services in the application layer
which adds a supplementary level of complexity.
”[/quote]

O texto em negrito do DDD é praticamente o mesmo do PoEAA.

[quote=Lezinho]“Client Layer”?

Client Layer é qualquer camada que faça uso de outra camada…[/quote]

Quem disse o contrário?

Estamos falando de camadas; repositório não é camada, entity não é camada, aggregate não é camada… Isso sim é padrão :wink:

Aqui deu a entender que seus Actions poderiam estar na camada de aplicação. O que não é o caso certo?

[quote=Lezinho][quote=Domain Driven Design]“While using Services, is important to keep the domain layer
isolated. It is easy to get confused between services which
belong to the domain layer, and those belonging to the
infrastructure. There can also be services in the application layer
which adds a supplementary level of complexity.
”[/quote][/quote]

Quem está dizendo que os Services são os mesmos é você. Agora já temos 3 services. Sua citação confirma que Services do DDD não é o Service Layer. Ou seja, nada impede que tenhamos entities chamando repositorioes ou entities chamando services ja que estamos falando estritamente de services “which belong to the domain layer”.

Eu já estou achando a discussão confusa demais para entender mas só um pontinho:

Camadas (Layers) é um padrão sim