Pola Desain Repositori di Swift

Cara bersih untuk menanyakan model Anda

Masalah apa yang dipecahkannya?

Jika Anda perlu melakukan kueri objek model Anda dari lokasi yang berbeda dalam kode Anda berulang-ulang, repositori dapat sangat membantu untuk menyediakan titik entri tunggal untuk bekerja dengan model Anda dan menghapus kode kueri duplikat. Anda dapat mengambilnya lebih jauh dan menggunakannya dengan protokol, dengan cara ini Anda dapat dengan mudah mengganti implementasi (misalnya untuk pengujian unit) atau Anda dapat menggunakannya dengan obat generik untuk membuat abstraksi generik yang lebih * drum roll *. Dalam artikel ini saya akan membahas semua kasus ini.

Membuat sketsa adegan.

Katakanlah Anda memiliki beberapa kode yang mengambil data dari API dan memetakan ini untuk memodelkan objek. Dalam contoh ini saya akan mengambil daftar artikel dari server.

Ini mungkin terlihat agak funky, tapi itu hanya RxSwift, menggunakan Moya sebagai lapisan abstraksi jaringan, tetapi itu tidak terlalu penting untuk memahami apa yang terjadi. Cara Anda mengambil data sepenuhnya terserah Anda.

Sepotong kode ini tidak

  1. Permintaan GET ke server
  2. Memetakan JSON yang dikembalikan ke array objek artikel
  3. Penutupan dipanggil ketika semua pekerjaan dilakukan.

Mengapa kita perlu repositori?

Yah, saat ini kami tidak. Jika Anda hanya memanggil API satu kali di seluruh basis kode Anda, menambahkan repositori mungkin berlebihan (atau seperti beberapa orang mengatakan rekayasa berlebihan).

Oke ... tapi kapan objek repositori nyaman digunakan?
Katakanlah basis kode Anda mulai tumbuh, dan Anda perlu menulis kode untuk mengambil artikel berulang kali. Anda mungkin mengatakan "mari salin kode dan tempel di mana pun Anda perlu mengambil semua artikel."

Tidak ada salahnya dilakukan, tidak ada yang mati. Kanan?

Pada saat itu, alarm merah besar akan mulai berkedip di otak Anda.

Halo repositori.

Repositori hanyalah objek yang merangkum semua kode untuk menanyakan model Anda di satu tempat, sehingga Anda memiliki satu entri titik jika Anda ingin mis. dapatkan semua artikel.

Mari kita buat objek repositori yang menyediakan API publik untuk mendapatkan artikel.

Sekarang kita dapat memanggil metode ini dan kita tidak perlu khawatir tentang apa yang terjadi di balik layar untuk mendapatkan artikel yang sebenarnya.
Panggil saja metode ini, dan Anda mendapatkan artikel. Bagus kan?
Tapi tunggu, masih ada lagi!

Tangani semua interaksi artikel

Kita dapat menggunakan repositori untuk menambahkan lebih banyak metode untuk berinteraksi dengan objek model kita. Sering kali Anda ingin melakukan operasi CRUD (membuat, membaca, memperbarui, menghapus) pada model Anda. Nah, tambahkan saja logika untuk operasi ini di repositori.

Ini membuat API yang bagus untuk digunakan di seluruh kode Anda, tanpa harus mengulang kode yang sama berulang-ulang.

Dalam praktiknya, penggunaan repositori akan terlihat seperti ini.

Cukup bagus dan mudah dibaca, bukan? Tapi, tunggu, ini jadi lebih baik.

Power-up: protokol

Dalam kode sebelumnya, saya selalu menggunakan contoh 'mendapatkan data dari API'. Tetapi bagaimana jika Anda perlu menambahkan dukungan untuk memuat data dari file JSON lokal alih-alih sumber online.

Jika Anda membuat protokol yang mencantumkan nama metode, Anda bisa membuat implementasi untuk API online dan satu untuk mendapatkan data offline.

Ini bisa terlihat seperti ini.

Protokol hanya mengatakan ‘jika Anda mematuhi saya, Anda harus memiliki metode ini tanda tangan, tapi saya tidak peduli dengan implementasi yang sebenarnya!

Jadi itu hebat, Anda bisa membuat WebArticleRepository dan LocalArticleRepository. Mereka berdua memiliki semua metode yang tercantum dalam protokol, tetapi Anda dapat menulis 2 implementasi yang sama sekali berbeda.

Penyalaan: Pengujian Unit

Penggunaan protokol juga sangat nyaman ketika Anda ingin menguji unit kode Anda, karena Anda bisa membuat objek lain yang mengimplementasikan protokol repositori, tetapi mengembalikan data tiruan.

Jika Anda menggunakan ini bersama dengan injeksi dependensi, sangat mudah untuk menguji objek tertentu.

Sebuah contoh

Katakanlah Anda memiliki model tampilan, dan model tampilan mendapatkan datanya melalui repositori.

Jika Anda ingin menguji model tampilan, Anda terjebak dengan artikel yang akan diambil dari web.
Ini sebenarnya bukan yang kita inginkan. Kami ingin pengujian kami menjadi deterministik sebanyak mungkin. Dalam hal ini, artikel yang diambil dari web dapat berubah dari waktu ke waktu, mungkin tidak ada koneksi internet pada saat tes berjalan, server bisa turun, ... ini semua adalah skenario yang mungkin di mana pengujian kami akan gagal, karena mereka adalah di luar kendali kami. Dan ketika kami menguji, kami ingin / perlu memegang kendali.

Untungnya sebenarnya sangat mudah untuk menyelesaikan ini.

Halo, injeksi ketergantungan.

Anda hanya perlu mengatur properti articleRepo melalui penginisialisasi. Kasing default, akan menjadi yang Anda inginkan untuk kode produksi Anda dan ketika Anda menulis tes unit, Anda dapat menukar repositori dengan versi tiruan Anda.

Tapi mungkin Anda berpikir, bagaimana dengan tipenya? WebArticleRepository bukan MockArticleRepository, jadi kompiler tidak akan mengeluh? Ya, tidak jika Anda menggunakan protokol sebagai tipe. Dengan cara ini kami memberi tahu kompiler, mengizinkan semuanya selama itu sesuai dengan protokol ArticleRepository (yang dilakukan oleh Web dan MockArticleRepository).

Kode akhir akan terlihat seperti ini.

Dan dalam pengujian unit Anda, Anda bisa menukar keluar seperti ini.

Sekarang Anda memiliki kendali penuh atas data apa yang dikembalikan oleh repositori Anda.

Super power-up: obat generik

Anda dapat mengambil ini lebih jauh, dengan menggunakan obat generik. Jika Anda memikirkannya, sebagian besar repositori selalu memiliki operasi yang sama

  1. dapatkan semua hal
  2. dapatkan beberapa hal
  3. masukkan beberapa hal
  4. hapus sesuatu
  5. perbarui sesuatu

Ya satu-satunya hal yang berbeda adalah kata 'benda', jadi ini mungkin kandidat yang sangat baik untuk menggunakan protokol dengan obat generik. Mungkin terdengar rumit, tetapi sebenarnya cukup sederhana untuk dilakukan.

Pertama kita akan mengubah nama protokol menjadi Repository, untuk membuatnya lebih ... generik ic
Dan kemudian kita akan menghapus semua jenis Artikel, dan menggantinya dengan sihir T. Tapi huruf T hanyalah pengganti untuk ... apa pun yang kita inginkan. Kita hanya perlu menandai T sebagai tipe protokol yang terkait.

Jadi sekarang kita dapat menggunakan protokol ini untuk objek model yang kita miliki.

1. Gudang artikel

Kompiler akan menyimpulkan jenis T ke Artikel, karena dengan menerapkan metode, kami telah menentukan apa itu T. Dalam hal ini objek Artikel.

2. Repositori Pengguna

Itu dia.

Saya harap Anda menikmati artikel ini dan jika Anda memiliki pertanyaan atau komentar, tanyakan di bawah ini atau hubungi saya di Twitter dan mari ngobrol.