Ketergantungan Injeksi vs Metode Statis

21

Saya melakukan diskusi yang menarik hari ini dengan pengembang lain tentang cara mendekati kelas dengan metode yang menerima string dan string output.

Bayangkan sesuatu seperti yang berikut ini yang sepenuhnya dibuat untuk tujuan contoh

public string GetStringPart(string input)
{ 
   //Some input validation which is removed for clarity

   if(input.Length > 5)
        return input.Substring(0,1);

   if(input.Substring(0,1) == "B")
        return input.Substring(0,3);

   return string.empty;
}

Sebuah fungsi yang memiliki beberapa logika berdasarkan input stringnya ditambahkan ke proyek menggunakan DI dan memiliki Container DI di tempat. Apakah Anda menambahkan kelas baru ini dengan antarmuka dan menyuntikkannya di tempat yang diperlukan, atau akankah Anda menjadikannya kelas statis? Apa pro dan kontra dari masing-masing? Mengapa Anda (atau tidak) ingin membuat ini digunakan dengan injeksi konstruktor daripada hanya diakses ketika diperlukan di mana saja.

James
sumber
1
@Wan Untuk metode pembantu yang tidak digunakan untuk abstraksi. Contoh: Apache FileUtils.
Walfrat
3
@ Ewan: metode statis tanpa efek samping adalah jenis metode terbaik, karena mudah dimengerti dan mudah diuji.
JacquesB
1
tetapi mereka membuatnya tidak mungkin untuk menguji hal-hal yang bergantung pada mereka
Ewan
3
@ Ewan Eh, tidak juga. Apakah Math.Max ​​() buruk karena statis? Jika Anda menguji metode statis Anda dan berfungsi, Anda dapat menggunakannya dengan aman pada metode lain tanpa masalah. Jika yang statis gagal, tesnya akan menangkapnya.
T. Sar - Pasang kembali Monica
1
jika 'statis' dijamin tidak ada efek samping saya mungkin dapat melihat argumennya. tapi tidak.
Ewan

Jawaban:

25

Tidak ada alasan mengapa ini perlu disuntikkan. Ini hanya sebuah fungsi, tidak memiliki dependensi, jadi panggil saja. Bahkan bisa statis jika Anda ingin terlihat murni. Seseorang dapat menulis unit test melawan ini tanpa kesulitan. Jika digunakan di kelas lain, tes unit masih bisa ditulis.

Tidak perlu untuk abstrak fungsi tanpa ketergantungan, itu berlebihan.

Jika ini menjadi lebih kompleks maka mungkin melewati antarmuka ke konstruktor atau metode dijamin. Tapi, saya tidak akan menyusuri jalan itu kecuali saya memiliki GetStringPartlogika yang kompleks berdasarkan lokasi, dll.

Jon Raynor
sumber
2
Ini jawaban yang benar! Ke buruknya jawaban kargo-kultus telah diterima.
JacquesB
3
bahwa fungsi tidak memiliki ketergantungan bukan itu intinya. masalahnya adalah ketika hal-hal lain bergantung pada fungsinya dan menjadi sangat erat dengannya
Ewan
2
Bagaimana jika fungsinya berubah dalam 6 bulan dan tidak begitu murni, tetapi sudah digunakan di banyak tempat. Ini tidak dapat diperluas sebagai statis dan juga bukan sesuatu yang dapat diisolasi dari mengkonsumsi tes unit kelas. Jika ada sedikit kemungkinan perubahan, saya akan menyuntiknya. Yang mengatakan, saya terbuka untuk mendengarkan argumen yang berlawanan, itulah inti dari posting ini. Apa kerugian dari disuntikkan dan positif dari statis?
James
1
Secara umum, orang yang membahas injeksi ketergantungan pada situs web ini, tidak memerlukan injeksi ketergantungan. Karenanya bias terhadap kompleksitas yang tidak perlu.
Frank Hileman
2
@James Jika fungsi menjadi kurang murni, Anda melakukan sesuatu yang salah dan fungsi itu mungkin tidak didefinisikan dengan baik sejak awal. Menghitung luas kuadrat seharusnya tidak tiba-tiba membutuhkan panggilan basis data atau menyebarkan pembaruan visual untuk UI. Bisakah Anda bayangkan skenario di mana metode "Substring" tiba-tiba menjadi tidak murni?
T. Sar - Pasang kembali Monica
12

Inilah sebabnya

class DOSClient {
    OrderParser orderParser;
    string orderCode;

    DOSClient(OrderParser orderParser, string ordercode) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
    }
    void DisplayOrderCode() {
        Console.Write( "Prefix: " + orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

class GUIClient {
    OrderParser orderParser;
    string orderCode;
    GUI gui;

    GUIClient(OrderParser orderParser, string ordercode, GUI gui) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
        this.gui = gui;
    }

    void DisplayOrderCode() {
        gui.Prefix( orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

 

class OrderParserUS : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 5)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "B")
            return input.Substring(0,3);

        return string.empty;
    }
}

class OrderParserEU : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 6)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "#")
            return input.Substring(0,3);

        return string.empty;
    }
}

Jika Anda menggunakan metode statis tidak akan ada cara untuk mengubah perilaku GetStringParttanpa menghancurkan perilaku lama atau mencemari dengan logika kondisional. Memang benar statika adalah global jahat yang menyamar tetapi fakta bahwa mereka menonaktifkan polimorfisme adalah keluhan utama saya tentang mereka. Metode statis bukan kelas satu dalam bahasa OOP. Dengan memberikan metode objek untuk hidup, bahkan satu tanpa keadaan, kita membuat metode portabel. Perilakunya dapat ditularkan seperti nilai variabel.

Di sini saya membayangkan sebuah sistem yang perlu berperilaku sedikit berbeda ketika dikerahkan di Eropa kemudian ketika dikerahkan di AS. Alih-alih memaksa kedua sistem untuk memuat kode yang hanya dibutuhkan oleh yang lain, kita dapat mengubah perilaku dengan mengontrol objek parsing pesanan apa yang diinjeksikan ke klien. Ini memungkinkan kami untuk menahan penyebaran detail kawasan. Itu juga membuatnya mudah untuk menambahkan OrderParserCanada tanpa harus menyentuh parser yang ada.

Jika itu tidak ada artinya bagi Anda, maka sebenarnya tidak ada argumen yang bagus untuk ini.

BTW, GetStringPartadalah nama yang mengerikan.

candied_orange
sumber
* Ngeri dengan gaya kode kurung * Saya kira Anda seorang programmer Java yang mencoba menulis kode C #? Membutuhkan seseorang untuk tahu yang saya kira. :)
Neil
Pertanyaannya tidak spesifik untuk bahasa, lebih lanjut tentang desain. Masalah saya dengan metode statis adalah mereka mencegah isolasi kode untuk pengujian. Pengembang yang saya ajak bicara berpikir saya terlalu mengandalkan DI dan terkadang metode ekstensi / metode statis relevan. Saya pikir mungkin dalam hal yang jarang terjadi tetapi tidak sebagai tujuan umum. Diskusi yang sedang berlangsung yang saya rasa bagus untuk dibahas lebih lanjut. Saya juga setuju dengan kasus Anda untuk polimorfisme.
James
Pengujian adalah alasan tetapi ada lebih banyak. Saya tidak suka menyalahkan ini karena pengujian terlalu banyak karena itu baru mulai orang mengkritik pengujian. Fakta sederhananya adalah programmer prosedural tidak menyukainya jika Anda tidak memprogram secara prosedural.
candied_orange
Tidak bisakah Anda mengatakannya begitu saja static getStringPartEU()? Contoh Anda hanya masuk akal jika ada metode lain di kelas itu yang juga memerlukan perawatan khusus UE dan harus diperlakukan sebagai satu unit.
Robert Harvey
2
Anda pasti berdebat mendukung kompleksitas yang tidak perlu. Semuanya dapat memiliki lebih banyak kode yang ditambahkan ke dalamnya. Hal-hal yang perlu diubah, harus mudah dimodifikasi, tetapi Anda tidak boleh mencoba memprediksi apa yang harus diubah di masa depan. Bidang statis dapat identik dengan variabel global, tetapi metode statis dapat murni, jenis metode terbaik.
Frank Hileman