React Native - Apakah menggunakan singleton alternatif terbaik untuk DI?


8

Saya sudah banyak membaca tentang pola tunggal dan bagaimana itu "buruk" karena membuat kelas-kelas menggunakannya sulit untuk diuji sehingga harus dihindari. Saya telah membaca beberapa artikel yang menjelaskan bagaimana singleton dapat diganti dengan suntikan ketergantungan, tetapi tampaknya tidak perlu bagi saya.

Inilah masalah saya sedikit lebih detail. Saya sedang membangun aplikasi seluler menggunakan React Native dan saya ingin membuat klien REST yang akan berkomunikasi dengan server, mendapatkan data, memposting data, dan menangani login (menyimpan token login dan mengirimkannya dengan setiap permintaan setelah login).

Rencana awal saya adalah membuat objek tunggal (RESTClient) yang akan digunakan aplikasi saya pada awalnya untuk masuk dan kemudian membuat permintaan mengirim kredensial jika diperlukan. Pendekatan DI tampaknya sangat rumit bagi saya (mungkin karena saya tidak pernah menggunakan DI sebelumnya) tetapi saya menggunakan proyek ini untuk belajar sebanyak mungkin sehingga saya ingin melakukan yang terbaik di sini. Setiap saran dan komentar sangat dihargai.

Sunting: Saya sekarang sadar saya telah menjawab pertanyaan saya dengan buruk. Saya ingin beberapa panduan tentang cara menghindari pola tunggal di RN dan haruskah saya melakukannya. Untungnya Samuel memberi saya jawaban yang saya inginkan. Masalah saya adalah saya ingin menghindari pola tunggal dan menggunakan DI, tetapi tampaknya sangat rumit untuk mengimplementasikannya dalam React Native. Saya melakukan riset lebih lanjut dan mengimplementasikannya menggunakan sistem konteks Reacts.

Bagi siapa pun yang tertarik, inilah cara saya melakukannya. Seperti saya katakan, saya menggunakan konteks di RN yang merupakan sesuatu seperti alat peraga tetapi itu disebarkan ke setiap komponen.

Di komponen root saya memberikan dependensi yang diperlukan seperti ini:

export default class Root extends Component {
  getChildContext() {
    restClient: new MyRestClient();
  }

  render() {...}
}
Root.childContextTypes = {restClient: PropTypes.object};

Sekarang restClient tersedia di semua komponen di bawah Root. Saya dapat mengaksesnya seperti ini.

export default class Child extends Component {
  useRestClient() {
    this.context.restClient.getData(...);
  }

  render() {...}
}
Child.contextTypes = {restClient: PropTypes.object}

Ini secara efektif memindahkan pembuatan objek dari logika dan memisahkan implementasi klien REST dari komponen saya.


3
Pertimbangkan untuk mengubah judul pertanyaan. Saat ini REST dan klien adalah elemen yang tidak relevan. Satu-satunya pertanyaan di sini adalah: Apakah singleton alternatif terbaik untuk DI dalam situasi spesifik saya? .
Laiv

Saya tidak tahu banyak tentang bereaksi, tetapi secara umum DI adalah konsep sederhana. Jika Anda merasa rumit, saya kira Anda belum membaca / mendengar penjelasan yang baik.
Ben Aaronson

Jawaban:


15

Injeksi ketergantungan tidak perlu rumit sama sekali, dan itu benar-benar layak untuk dipelajari dan digunakan. Biasanya rumit dengan penggunaan kerangka kerja injeksi ketergantungan, tetapi mereka tidak perlu.

Dalam bentuk yang paling sederhana, injeksi dependensi melewati dependensi alih-alih mengimpor atau membangunnya. Ini bisa dipuji dengan hanya menggunakan parameter untuk apa yang akan diimpor. Katakanlah Anda memiliki komponen bernama MyListyang perlu digunakan RESTClientuntuk mengambil beberapa data dan menampilkannya kepada pengguna. Pendekatan "tunggal" akan terlihat seperti ini:

import restClient from '...' // import singleton

class MyList extends React.Component {
  // use restClient and render stuff
}

Ini sangat cocok MyListuntuk pasangan restClient, dan tidak mungkin Anda bisa menguji unit MyListtanpa pengujian restClient. Pendekatan DI akan terlihat seperti ini:

function MyListFactory(restClient) {
  class MyList extends React.Component {
    // use restClient and render stuff
  }

  return MyList
}

Hanya itu yang diperlukan untuk menggunakan DI. Ini menambah paling banyak dua baris kode dan Anda bisa menghilangkan impor. Alasan mengapa saya memperkenalkan fungsi baru "pabrik" adalah karena AFAIK Anda tidak dapat melewatkan parameter konstruktor tambahan di Bereaksi, dan saya lebih suka untuk tidak meneruskan hal-hal ini melalui properti Bereaksi karena itu tidak portabel dan semua komponen induk harus tahu untuk melewati semua alat peraga untuk anak-anak.

Jadi sekarang Anda memiliki fungsi untuk membangun MyListkomponen, tetapi bagaimana Anda menggunakannya? Pola DI memunculkan rantai ketergantungan. Katakanlah Anda memiliki komponen MyAppyang digunakan MyList. Pendekatan "tunggal" adalah:

import MyList from '...'
class MyApp extends React.Component {
  render() {
    return <MyList />
  }
}

Pendekatan DI adalah:

function MyAppFactory(ListComponent) {
  class MyApp extends React.Component {
    render() {
      return <ListComponent />
    }
  }

  return MyApp
}

Sekarang kita dapat menguji MyApptanpa menguji MyListsecara langsung. Kami bahkan dapat menggunakan kembali MyAppdengan daftar yang sangat berbeda. Pola ini menggelembung hingga ke akar komposisi . Di sinilah Anda memanggil pabrik Anda dan mengirimkan semua komponen.

import RESTClient from '...'
import MyListFactory from '...'
import MyAppFactory from '...'

const restClient = new RESTClient(...)
const MyList = MyListFactory(restClient)
const MyApp = MyAppFactory(MyList)

ReactDOM.render(<MyApp />, document.getElementById('app'))

Sekarang sistem kami menggunakan instance tunggal RESTClient, tetapi kami telah mendesainnya sedemikian rupa sehingga komponen dapat digabungkan secara longgar dan mudah diuji.


Jika Anda tidak keberatan, saya ingin membuat referensi untuk jawaban Anda dari saya, karena saya pikir itu menggambarkan dengan sangat baik poin-poin yang saya sebutkan secara dangkal.
Laiv

2
@Laiv, saya pikir istilah "DIA orang miskin" tidak lagi populer, lebih disukai "DI murni". Meskipun tidak dimaksudkan, yang pertama terdengar terlalu negatif karena menyiratkan wadah IoC "lebih kaya".
David Arno

Ini. Saya pikir Ketergantungan Injeksi sangat rumit ketika saya pertama kali melihatnya, tetapi setelah beberapa saat itu sangat mudah untuk dipahami. Dan @Samuel menjelaskannya dengan baik!
Rhys Johns

1
@Samuel Jadi, untuk menerapkan DI dengan benar dalam React, saya perlu membuat pabrik untuk setiap komponen? Juga dalam contoh Anda, bukankah seharusnya MyAppFactorymengembalikan MyAppkelas?
Mateo Hrastnik

@MattHammond Komponen sederhana yang tidak memiliki dependensi tidak memerlukan pabrik. Dan ini adalah cara saya melakukannya, mungkin ada pendekatan lain untuk DI dalam Bereaksi yang lebih baik, tetapi saya bertujuan untuk kesederhanaan di sini. Terima kasih atas koreksinya; Saya sudah memperbaikinya sekarang.
Samuel

5

Menurut tempat Anda (belajar), jawaban paling sederhana adalah tidak, lajang bukan alternatif terbaik untuk Dependency Injection .

Jika belajar adalah tujuannya, Anda akan menemukan DI menjadi sumber daya yang lebih berharga di kotak alat Anda daripada Singleton. Ini mungkin terlihat rumit, tetapi kurva belajarnya hampir pada semua yang Anda harus pelajari dari awal. Jangan berbaring di zona nyaman Anda atau tidak akan ada belajar sama sekali.

Secara teknis, ada sedikit perbedaan antara singleton dan single instance (apa yang saya pikir Anda coba lakukan). Belajar DI Anda akan menyadari bahwa Anda dapat menyuntikkan satu contoh di seluruh kode. Anda akan menemukan kode Anda lebih mudah untuk diuji dan digabungkan secara longgar. ( Untuk lebih jelasnya lihat jawaban Samuel )

Tapi jangan berhenti di sini. Apakah menerapkan kode yang sama dengan Singleton. Kemudian bandingkan kedua pendekatan tersebut.

Memahami dan membiasakan diri dengan kedua implementasi akan memungkinkan Anda untuk mengetahui kapan mereka cocok dan mungkin Anda akan berada dalam posisi untuk menjawab sendiri pertanyaan itu.

Sekarang, selama pelatihan, ketika Anda memalsukan Golden Hammers Anda , jadi jika Anda memutuskan untuk menghindari belajar DI, kemungkinan besar Anda akan akhirnya menerapkan lajang setiap kali Anda membutuhkan DI.


0

Saya setuju dengan jawaban lain bahwa mempelajari apa itu DI dan bagaimana menggunakannya adalah ide yang bagus.

Yang mengatakan, peringatan bahwa lajang membuat pengujian terlalu keras biasanya dibuat oleh orang yang menggunakan bahasa yang diketik secara statis (C ++, C #, Java, dll . ) .
Berbeda dengan bahasa yang dinamis (Javascript, PHP, Python, Ruby, dll.) , Biasanya sulit untuk mengganti singleton dengan implementasi tes khusus daripada jika Anda menggunakan DI.

Dalam hal ini, saya sarankan menggunakan desain yang terasa lebih alami untuk Anda dan co-developer Anda, karena itu akan cenderung menghindari kesalahan. Jika itu menghasilkan lajang, jadilah itu.

(Tapi sekali lagi: Pelajari DI sebelum Anda membuat keputusan itu.)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.