Padrão de Design do Repositório no Swift

Uma maneira limpa de consultar seus modelos

Qual problema isso resolve?

Se você precisar consultar seus objetos de modelo de diferentes locais em seu código repetidamente, um repositório pode ser realmente útil para fornecer um ponto de entrada única para trabalhar com seus modelos e remover o código de consulta duplicado. Você pode ir ainda mais longe e usá-lo com protocolos, dessa maneira você pode facilmente mudar implementações (por exemplo, para testes de unidade) ou pode usá-lo com genéricos para criar uma abstração mais genérica. Neste artigo, abordarei todos esses casos.

Esboçando a cena.

Digamos que você tenha algum código que busca dados de uma API e mapeia isso para modelar objetos. Neste exemplo, buscarei uma lista de artigos de um servidor.

Isso pode parecer um pouco estranho, mas é apenas o RxSwift, usando Moya como a camada de abstração de rede, mas isso realmente não importa para entender o que está acontecendo. A maneira como você recupera seus dados depende totalmente de você.

Este pedaço de código não

  1. Uma solicitação GET para o servidor
  2. Mapeia o JSON retornado para uma matriz de objetos Article
  3. O fechamento é chamado quando todo o trabalho é concluído.

Por que precisamos de um repositório?

Bem, no momento não. Se você chamar a API apenas uma vez em toda a sua base de códigos, a adição de um repositório pode ser um exagero (ou, como alguns podem dizer, exagerar na engenharia).

Ok ... mas quando é conveniente usar um objeto de repositório?
Digamos que sua base de código comece a crescer e você precise escrever o código para buscar os artigos repetidamente. Você pode dizer "vamos copiar o código e colá-lo sempre que precisar buscar todos os artigos".

Nenhum dano causado, ninguém morreu. Direita?

Nesse momento, um grande alarme vermelho deve começar a piscar em seu cérebro.

Olá repositório.

Um repositório é apenas um objeto que encapsula todo o código para consultar seus modelos em um único local, para que você tenha um ponto de entrada único, se desejar, por exemplo. obtenha todos os artigos.

Vamos criar um objeto de repositório que fornece uma API pública para obter os artigos.

Agora podemos chamar esse método e não precisamos nos preocupar com o que acontece nos bastidores para obter os artigos reais.
Basta chamar o método e você obtém os artigos. Legal né?
Mas espere, tem mais!

Manipular todas as interações de artigos

Podemos usar o repositório para adicionar mais métodos para interagir com nosso objeto de modelo. Na maioria das vezes você deseja executar operações CRUD (criar, ler, atualizar, excluir) em seu modelo. Bem, basta adicionar a lógica para essas operações no repositório.

Isso torna uma API agradável para usar em todo o seu código, sem precisar repetir o mesmo código repetidamente.

Na prática, o uso de um repositório ficaria assim.

Muito bom e legível, certo? Mas espere, isso fica ainda melhor.

Ligação: protocolos

No código anterior, sempre usei o exemplo de 'obtenção de dados de uma API'. Mas e se você precisar adicionar suporte para carregar dados de um arquivo JSON local em vez de uma fonte online.

Bem, se você criar um protocolo que lista os nomes dos métodos, poderá criar uma implementação para a API online e outra para disponibilizar os dados offline.

Isso pode ser assim.

Um protocolo apenas diz "se você estiver em conformidade comigo, precisará ter assinaturas desses métodos, mas não me importo com a implementação real!"

Então, isso é ótimo, você pode criar um WebArticleRepository e um LocalArticleRepository. Ambos terão todos os métodos listados no protocolo, mas você pode escrever duas implementações totalmente diferentes.

Ligação: Teste de Unidade

O uso de protocolos também é realmente conveniente quando você deseja testar seu código de unidade, porque você pode simplesmente criar outro objeto que implemente o protocolo do repositório, mas retorna dados simulados.

Se você usar isso junto com a injeção de dependência, será muito fácil testar um objeto específico.

Um exemplo

Digamos que você tenha um modelo de visualização, e o modelo de visualização obtém seus dados por meio de um repositório.

Se você deseja testar o modelo de visualização, está preso aos artigos que serão buscados na Web.
Na verdade, não é isso que queremos. Queremos que nosso teste seja determinístico, tanto quanto possível. Nesse caso, os artigos recuperados da Web podem mudar com o tempo, não haver conexão com a Internet no momento em que os testes são executados, o servidor pode estar inoperante ... esses são todos os cenários possíveis nos quais nossos testes falhariam, porque são fora de nosso controle. E quando testamos, queremos / precisamos estar no controle.

Felizmente, é realmente muito simples resolver isso.

Olá, injeção de dependência.

Você só precisa definir a propriedade articleRepo através do inicializador. O caso padrão será o desejado para o seu código de produção e, quando você escrever um teste de unidade, poderá trocar o repositório pela sua versão simulada.

Mas talvez você esteja pensando, bem, e os tipos? Um WebArticleRepository não é um MockArticleRepository; portanto, o compilador não irá reclamar? Bem, não se você usar o protocolo como um tipo. Dessa forma, informamos ao compilador, permitimos tudo, desde que esteja em conformidade com o protocolo ArticleRepository (o que a Web e o MockArticleRepository fazem).

O código final ficaria assim.

E no seu teste de unidade, você pode trocá-lo assim.

Agora você tem controle total sobre quais dados seu repositório retorna.

Super power-up: genéricos

Você pode levar isso ainda mais longe, usando genéricos. Se você pensar bem, a maioria dos repositórios sempre terá as mesmas operações

  1. pegue todas as coisas
  2. pegue algumas das coisas
  3. insira algumas coisas
  4. excluir coisa
  5. atualizar uma coisa

Bem, a única coisa diferente é a palavra "coisa"; portanto, esse pode ser um excelente candidato para usar um protocolo com genéricos. Pode parecer complicado, mas na verdade é bem simples de fazer.

Primeiro, renomearemos o protocolo para Repositório, para torná-lo mais ... genérico ".
E então removeremos todos os tipos de artigos e os substituiremos pelo mágico T. Mas a letra T é apenas um substituto para ... qualquer coisa que queremos que seja. Nós só precisamos marcar T como o tipo associado do protocolo.

Portanto, agora podemos usar esse protocolo para qualquer objeto de modelo que tenhamos.

1. Repositório de artigos

O compilador inferirá o tipo de T para Artigo, porque, ao implementar os métodos, especificamos o que é T. Nesse caso, um objeto Article.

2. Repositório do Usuário

É isso aí.

Espero que você tenha gostado do artigo e, se tiver alguma pergunta ou comentário, basta perguntar abaixo ou entrar em contato comigo no Twitter e vamos conversar.