Como projetar um padrão de repositório que possa manipular o carregamento de dados relacionais por caso de uso?

5

Estamos projetando um grande refatorador na base de código do meu sistema da empresa. Um dos pontos de refatoração é a definição (real) do modelo de lógica / domínio de negócios. Neste momento, todo repositório na base de código irá apenas buscar todos os dados possíveis relacionados à entidade, e para "otimizar" isso, tudo está sendo buscado em arrays ao invés de objetos (tecnicamente, hashmaps key-value, mas em PHP eles ' re chamados matrizes).

Agora, gostaria de apresentar o uso real de objetos de modelo que encapsulam a lógica de negócios (chamando métodos como businessObject.canTransitionToNextProcessPhase() em vez de fazer um monte de if/else em um controlador, resultando em legibilidade 0.

Para a primeira parte deste design, identifico quais dados relacionais são obrigatórios para cada entidade. Pode ser facilmente identificado quando uma entidade é dependente. Por exemplo: um Entry deve sempre carregar o Category e o User (autor). No entanto, ao buscar um User , você não precisa necessariamente carregar todas as entradas, amigos, etc.

Agora, em alguns casos específicos , ao carregar um User , talvez você queira carregar todos os Entries deles também. Como projetar um padrão de repositório que permite carregar esses dados relacionais nesses casos particulares?

Por exemplo, use o método [email protected](int) :

O método deve receber parâmetros de opção que permitam decidir se devem ser carregados relacionamentos adicionais que não sejam os padrões? (por exemplo: ContactInfo é o padrão, a lista de Entries é adicional).

Em vez disso, ele deve ser configurado em um método de encadeamento como repo.alsoLoad('entries').getById(id) ? (no entanto, isso parece replicar a API do ORM, eu acho).

Por favor, note que o objetivo deste projeto de padrão de repositório não é apenas uma camada que cobre o ORM desnecessariamente. Os métodos recuperarão os dados com base nos casos de uso de negócios: getAllInvoicesFromCurrentCycle() em vez de getAll(hashamp /* with 5 key/values to be passed directly to the ORM's where clause*/) , já que este último não oferece nenhum benefício (nem legibilidade) (pode muito bem usar o ORM diretamente).

Eu atualizarei a pergunta se mais esclarecimentos forem necessários.

    
por Christopher Francisco 22.02.2017 / 22:42
fonte

1 resposta

2

Eu sugeriria ter uma classe UserRepository e UserFriendRepository separadas. O UserFriendRepository pode pegar um User ou UserId em seu construtor.

(A menos que Usuários e Amigos sejam sempre tratados juntos e salvos juntos - então você desejaria apenas uma classe de repositório - mas não acho que esse seja o seu caso.)

A intenção do padrão Repositório é trazer uma camada de simplicidade, clareza (mais fácil para os desenvolvedores trabalharem com classes Usuário e Amigo do que classes de acesso a dados de baixo nível) e testabilidade de unidade. É uma camada de abstração onde, digamos, "cache" poderia ser adicionado (ou alterado ou removido) sem que o código do cliente soubesse.

Adendo com base no comentário:

Eu pessoalmente tive mais sorte em manter a camada Repositório simples (caso contrário, eu me re-implemento o ORM / ficando amarrado em nós). Eu prefiro chamar UserFriendRepo.Get () quando necessário e UserOrderRepo.Get () quando necessário; em vez de um repositório do usuário mais complexo que pode ser passado dicas para carregar [amigos] e [ordens].

No entanto, um repositório "mais inteligente" pode ser garantido se o carregamento rápido e / ou o carregamento lento ajudarem o desempenho de seu aplicativo específico, ou se ele for mais intuitivo para os desenvolvedores em sua loja etc. Padrões são apenas abordagens gerais que você está livre para afinar.

    
por 24.02.2017 / 20:51
fonte