Pertanyaan Apa itu injeksi ketergantungan?


Ada beberapa pertanyaan yang sudah diposkan dengan pertanyaan khusus tentang injeksi ketergantungan, seperti kapan menggunakannya dan kerangka apa yang ada untuk itu. Namun,

Apa itu injeksi ketergantungan dan kapan / mengapa harus atau tidak seharusnya digunakan?


2626
2017-09-25 00:28


asal


Jawaban:


Pada dasarnya, alih-alih memiliki objek Anda menciptakan ketergantungan atau meminta objek pabrik untuk membuat satu untuk mereka, Anda melewatkan dependensi yang diperlukan ke objek secara eksternal, dan Anda menjadikannya masalah orang lain. Ini "seseorang" adalah salah satu objek lebih jauh grafik ketergantungan, atau injektor ketergantungan (kerangka kerja) yang membangun grafik ketergantungan. Ketergantungan seperti yang saya gunakan di sini adalah objek lain yang diperlukan objek saat ini untuk memiliki referensi.

Salah satu keuntungan utama dari injeksi ketergantungan adalah dapat membuat pengujian lebih mudah. Misalkan Anda memiliki objek yang konstruktornya melakukan sesuatu seperti:

public SomeClass() {
    myObject = Factory.getObject();
}

Ini bisa merepotkan ketika semua yang Anda ingin lakukan adalah menjalankan beberapa tes unit pada SomeClass, terutama jika myObject adalah sesuatu yang melakukan disk atau akses jaringan yang kompleks. Jadi sekarang Anda melihat mengejek myObject tetapi juga entah bagaimana mencegat panggilan pabrik. Keras. Sebaliknya, berikan objek sebagai argumen ke konstruktor. Sekarang Anda telah memindahkan masalah ke tempat lain, tetapi pengujian bisa menjadi lebih mudah. Buat saja myObject tiruan dan lewati itu. Konstruktor sekarang akan terlihat seperti:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Ini adalah salah satu gaya injeksi ketergantungan - melalui konstruktor. Beberapa mekanisme dimungkinkan.

  • Seperti tercantum dalam komentar, satu alternatif umum adalah mendefinisikan konstruktor yang tidak melakukan apa-apa, dan memiliki ketergantungan yang disalurkan melalui setter properti (h / t @MikeVella).
  • Martin Fowler mendokumentasikan alternatif ketiga (h / t @MarcDix), di mana kelas secara eksplisit mengimplementasikan antarmuka untuk dependensi yang mereka inginkan disuntikkan.

Ketika tidak menggunakan injeksi ketergantungan (seperti di kelas yang terlalu banyak bekerja di konstruktor mereka dll), itu cenderung menjadi jauh lebih sulit untuk mengisolasi komponen dalam pengujian unit.

Kembali pada tahun 2013 ketika saya menulis jawaban ini, ini adalah tema utama pada Google Testing Blog. Ini tetap merupakan keuntungan terbesar bagi saya, karena Anda mungkin tidak selalu membutuhkan fleksibilitas ekstra dalam desain run-time Anda (misalnya, untuk pencari layanan atau pola serupa), tetapi Anda seringkali harus dapat mengisolasi kelas Anda selama pengujian.


1633
2017-09-25 00:49



Definisi terbaik yang saya temukan sejauh ini satu oleh James Shore:

"Ketergantungan Injeksi" adalah 25 dolar   istilah untuk konsep 5 sen. [...]   Ketergantungan injeksi berarti memberi   objek variabel instannya. [...].

Ada sebuah artikel oleh Martin Fowler yang mungkin terbukti berguna juga.

Injeksi ketergantungan pada dasarnya menyediakan objek yang dibutuhkan objek (dependensinya) daripada membuatnya mengkonstruksinya sendiri. Ini adalah teknik yang sangat berguna untuk pengujian, karena memungkinkan dependensi untuk diejek atau dihentikan.

Dependensi dapat disuntikkan ke objek dengan banyak cara (seperti injeksi konstruktor atau injeksi setter). Satu bahkan dapat menggunakan kerangka kerja injeksi ketergantungan khusus (misalnya Spring) untuk melakukan itu, tetapi mereka tentu tidak diperlukan. Anda tidak perlu kerangka kerja tersebut untuk memiliki injeksi ketergantungan. Instansiasi dan objek yang lewat (dependensi) secara eksplisit sama bagusnya dengan injeksi dengan kerangka kerja.


2058
2017-09-26 16:50



Saya menemukan contoh lucu ini dalam hal kopling longgar:

Aplikasi apa pun terdiri dari banyak objek yang berkolaborasi satu sama lain untuk melakukan beberapa hal yang berguna. Secara tradisional setiap objek bertanggung jawab untuk mendapatkan referensi sendiri ke objek dependen (dependensi) yang dikolaborasikan dengannya. Ini mengarah pada kelas-kelas yang sangat digabungkan dan kode yang sulit di-test.

Misalnya, pertimbangkan a Car obyek.

SEBUAH Car tergantung pada roda, mesin, bahan bakar, baterai, dll. untuk dijalankan. Secara tradisional, kami mendefinisikan merek dari objek dependen tersebut bersama dengan definisi dari Car obyek.

Tanpa Ketergantungan Injeksi (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Di sini, the Car obyek bertanggung jawab untuk menciptakan objek tergantung.

Bagaimana jika kita ingin mengubah jenis objek bergantungnya - katakan Wheel - setelah awal NepaliRubberWheel() tusukan? Kita perlu membuat ulang objek Mobil dengan ketergantungan barunya ChineseRubberWheel(), tetapi hanya Car pabrikan bisa melakukan itu.

Lalu apa hubungannya Dependency Injection lakukan kami untuk ...?

Ketika menggunakan injeksi ketergantungan, objek diberikan dependensinya pada waktu berjalan daripada waktu kompilasi (waktu pembuatan mobil). Sehingga kita sekarang dapat mengubah Wheel kapanpun kita mau. Di sini, the dependency (wheel) dapat disuntikkan Car pada waktu berjalan.

Setelah menggunakan injeksi ketergantungan:

Di sini, kami suntik itu ketergantungan (Roda dan Baterai) saat runtime. Maka istilahnya: Injeksi Ketergantungan. 

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Sumber: Memahami injeksi ketergantungan


507
2018-05-22 04:01



Ketergantungan Injeksi adalah praktik di mana objek dirancang dengan cara di mana mereka menerima contoh objek dari potongan kode lainnya, bukan membangunnya secara internal. Ini berarti bahwa setiap objek yang mengimplementasikan antarmuka yang diperlukan oleh objek dapat diganti tanpa mengubah kode, yang menyederhanakan pengujian, dan meningkatkan pemisahan.

Misalnya, pertimbangkan klausa ini:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

Dalam contoh ini, implementasi dari PersonService::addManager dan PersonService::removeManager akan membutuhkan instance dari GroupMembershipService untuk melakukan tugasnya. Tanpa Ketergantungan Injeksi, cara tradisional untuk melakukan ini adalah untuk membuat yang baru GroupMembershipService dalam konstruktor PersonService dan gunakan atribut instan itu di kedua fungsi. Namun, jika konstruktor dari GroupMembershipService memiliki beberapa hal yang diperlukan, atau lebih buruk lagi, ada beberapa inisialisasi "setter" yang perlu dipanggil di GroupMembershipService, kode tumbuh agak cepat, dan PersonServicesekarang tidak hanya bergantung pada GroupMembershipService tetapi juga segalanya itu GroupMembershipService tergantung pada. Selanjutnya, hubungannya dengan GroupMembershipService adalah hardcoded ke dalam PersonService yang berarti Anda tidak bisa "membongkar" a GroupMembershipService untuk tujuan pengujian, atau untuk menggunakan pola strategi di berbagai bagian aplikasi Anda.

Dengan Ketergantungan Injeksi, bukannya instantiating GroupMembershipService dalam diri Anda PersonService, Anda akan meneruskannya ke PersonService konstruktor, atau tambahkan Properti (pengambil dan penyetel) untuk menetapkan turunan lokalnya. Ini berarti bahwa Anda PersonService tidak perlu lagi khawatir tentang cara membuat GroupMembershipService, hanya menerima yang diberikan, dan bekerja dengan mereka. Ini juga berarti bahwa apa pun yang merupakan subclass dari GroupMembershipService, atau mengimplementasikan GroupMembershipService antarmuka dapat "disuntikkan" ke dalam PersonService, dan PersonService tidak perlu tahu tentang perubahan itu.


233
2017-09-25 06:49



Jawaban yang diterima adalah jawaban yang bagus - tetapi saya ingin menambahkan bahwa DI sangat mirip dengan menghindari konstanta hardcode klasik dalam kode.

Ketika Anda menggunakan beberapa konstanta seperti nama database, Anda akan dengan cepat memindahkannya dari bagian dalam kode ke beberapa file konfigurasi dan meneruskan variabel yang berisi nilai tersebut ke tempat yang diperlukan. Alasan untuk melakukan itu adalah bahwa konstanta ini biasanya berubah lebih sering daripada sisa kode. Misalnya jika Anda ingin menguji kode dalam basis data uji coba.

DI analog dengan ini dalam dunia pemrograman Berorientasi Objek. Nilai-nilai di sana bukannya literal konstan adalah objek utuh - tetapi alasan untuk memindahkan kode membuat mereka keluar dari kode kelas mirip - objek berubah lebih sering maka kode yang menggunakan mereka. Satu hal penting di mana perubahan semacam itu diperlukan adalah tes.


142
2018-01-06 18:33



Mari kita bayangkan bahwa Anda ingin pergi memancing:

  • Tanpa injeksi ketergantungan, Anda harus mengurus semuanya sendiri. Anda perlu mencari perahu, membeli pancing, mencari umpan, dll. Itu mungkin, tentu saja, tetapi itu menempatkan banyak tanggung jawab pada Anda. Dalam istilah perangkat lunak, itu berarti Anda harus melakukan pencarian untuk semua hal ini.

  • Dengan injeksi ketergantungan, orang lain mengurus semua persiapan dan menyediakan peralatan yang dibutuhkan untuk Anda. Anda akan menerima ("disuntikkan") perahu, pancing dan umpan - semua siap digunakan.


96
2017-10-22 04:47



Ini adalah penjelasan paling sederhana tentang Injeksi Ketergantungan dan Ketergantungan Kontainer Injeksi Yang pernah saya lihat:

Tanpa Injeksi Ketergantungan

  • Kebutuhan aplikasi Foo (mis. Pengontrol), jadi:
  • Aplikasi menciptakan Foo
  • Panggilan aplikasi Foo
    • Foo membutuhkan Bar (misalnya layanan), jadi:
    • Foo menciptakan Bar
    • Foo memanggil Bar
      • Bar membutuhkan Bim (layanan, repositori, ...), jadi:
      • Bar menciptakan Bim
      • Bar melakukan sesuatu

Dengan Injeksi Ketergantungan

  • Kebutuhan aplikasi Foo, yang membutuhkan Bar, yang membutuhkan Bim, jadi:
  • Aplikasi menciptakan Bim
  • Aplikasi membuat Bar dan memberinya Bim
  • Aplikasi membuat Foo dan memberinya Bar
  • Panggilan aplikasi Foo
    • Foo memanggil Bar
      • Bar melakukan sesuatu

Menggunakan Kontainer Injeksi Ketergantungan

  • Kebutuhan aplikasi Foo jadi:
  • Aplikasi mendapat Foo dari Container, jadi:
    • Wadah menciptakan Bim
    • Container menciptakan Bar dan memberinya Bim
    • Wadah membuat Foo dan memberinya Bar
  • Panggilan aplikasi Foo
    • Foo memanggil Bar
      • Bar melakukan sesuatu

Injeksi Ketergantungan dan ketergantungan Kontainer Injeksi adalah hal yang berbeda:

  • Ketergantungan Injeksi adalah metode untuk menulis kode yang lebih baik
  • DI Container adalah alat untuk membantu menyuntikkan dependensi

Anda tidak perlu wadah untuk melakukan injeksi ketergantungan. Namun wadah dapat membantu Anda.


80
2018-05-05 11:53



Mari kita coba contoh sederhana dengan Mobil dan Mesin kelas, mobil apa pun membutuhkan mesin untuk pergi ke mana pun, setidaknya untuk saat ini. Jadi di bawah ini bagaimana kode akan terlihat tanpa injeksi ketergantungan.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

Dan untuk instantiate kelas Mobil kita akan menggunakan kode berikut:

Car car = new Car();

Masalah dengan kode ini yang kami kombinasikan erat dengan GasEngine dan jika kami memutuskan untuk mengubahnya ke ElectricityEngine maka kami perlu menulis ulang kelas Mobil. Dan semakin besar aplikasi semakin banyak masalah dan sakit kepala kita harus menambahkan dan menggunakan jenis mesin baru.

Dengan kata lain dengan pendekatan ini adalah bahwa kelas Mobil tingkat tinggi kami tergantung pada kelas GasEngine tingkat yang lebih rendah yang melanggar Prinsip Ketergantungan Ketergantungan (DIP) dari SOLID. DIP menyarankan bahwa kita harus bergantung pada abstraksi, bukan kelas konkrit. Jadi untuk memuaskan ini kami memperkenalkan antarmuka IEngine dan menulis ulang kode seperti di bawah ini:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Sekarang kelas Mobil kami hanya bergantung pada antarmuka IEngine, bukan implementasi spesifik dari mesin. Sekarang, satu-satunya cara adalah bagaimana kita membuat turunan dari Mobil dan memberikannya kelas Engine beton yang nyata seperti GasEngine atau ElectricityEngine. Di situlah Injeksi Ketergantungan datang.

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Di sini kita pada dasarnya menyuntikkan (lulus) ketergantungan kita (contoh Mesin) ke konstruktor Mobil. Jadi sekarang kelas kami memiliki kopling longgar antara objek dan dependensi mereka, dan kami dapat dengan mudah menambahkan jenis mesin baru tanpa mengubah kelas Mobil.

Manfaat utama dari Injeksi Ketergantungan bahwa kelas lebih longgar digabungkan, karena mereka tidak memiliki dependensi hard-coded. Ini mengikuti Prinsip Ketergantungan Ketergantungan, yang telah disebutkan di atas. Alih-alih mengacu pada implementasi tertentu, kelas meminta abstraksi (biasanya antarmuka) yang disediakan untuk mereka ketika kelas dibangun.

Jadi pada akhirnya Injeksi ketergantungan hanyalah teknik untuk   mencapai kopling longgar antara objek dan dependensi mereka.   Daripada langsung memberi contoh dependensi yang dibutuhkan kelas   Untuk melakukan tindakannya, dependensi diberikan ke kelas   (paling sering) melalui injeksi konstruktor.

Juga ketika kita memiliki banyak dependensi itu adalah praktik yang sangat baik untuk menggunakan wadah Inversi Control (IOC) yang dapat kita ketahui antarmuka mana yang harus dipetakan ke mana implementasi konkret untuk semua dependensi kita dan kita dapat memilikinya menyelesaikan dependensi tersebut bagi kita ketika membangun objek kami. Sebagai contoh, kita bisa menentukan dalam pemetaan untuk wadah IoC bahwa IEngine ketergantungan harus dipetakan ke Mesin gas kelas dan ketika kami meminta wadah IoC untuk contoh dari kami Mobil kelas, itu secara otomatis akan membangun kita Mobil kelas dengan Mesin gas ketergantungan berlalu.

MEMPERBARUI: Menonton kursus tentang EF Core dari Julie Lerman baru-baru ini dan juga menyukai definisi singkatnya tentang DI.

Ketergantungan injeksi adalah pola untuk memungkinkan aplikasi Anda untuk disuntikkan   objek dengan cepat ke kelas yang membutuhkannya, tanpa memaksanya   kelas untuk bertanggung jawab atas objek-objek itu. Ini memungkinkan kode Anda   lebih longgar digabungkan, dan Entity Framework Core dihubungkan ke yang sama ini   sistem layanan.


77
2017-07-06 09:42



Bukankah "ketergantungan injeksi" hanya berarti menggunakan konstruktor parameter dan setter publik?

Artikel James Shore menunjukkan contoh-contoh berikut untuk perbandingan.

Konstruktor tanpa injeksi ketergantungan:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

Pembuat dengan injeksi ketergantungan:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}

44
2018-05-02 00:40