Pertanyaan Pola mana yang digunakan untuk penebangan? Ketergantungan Injeksi atau Pencari Layanan?


Pertimbangkan skenario ini. Saya memiliki beberapa logika bisnis yang sekarang dan nanti akan diminta untuk menulis ke log.

interface ILogger
{
    void Log(string stuff);
}

interface IDependency
{
    string GetInfo();
}

class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)
    {
        _dependency = dependency;
    }

    public string DoSomething(string input)
    {
        // Process input
        var info = _dependency.GetInfo();
        var intermediateResult = PerformInterestingStuff(input, info);

        if (intermediateResult== "SomethingWeNeedToLog")
        {
            // How do I get to the ILogger-interface?
        }

        var result = PerformSomethingElse(intermediateResult);

        return result;
    }
}

Bagaimana Anda akan mendapatkan antarmuka ILogger? Saya melihat dua kemungkinan utama;

  1. Lewati menggunakan Injeksi Ketergantungan pada konstruktor.
  2. Dapatkan melalui Service Locator tunggal.

Metode mana yang lebih Anda sukai, dan mengapa? Atau apakah ada pola yang lebih baik?

Memperbarui: Perhatikan bahwa saya tidak perlu login SEMUA panggilan metode. Saya hanya ingin mencatat beberapa kejadian (jarang) yang mungkin atau mungkin tidak terjadi dalam metode saya.


32
2018-04-21 11:48


asal


Jawaban:


Saya pribadi melakukan campuran keduanya.

Inilah konvensi saya:

  • Dari konteks statis - Lokasi Layanan
  • Dari konteks contoh - Injeksi Ketergantungan

Saya merasa ini memberi saya keseimbangan testability yang tepat. Saya merasa sedikit lebih sulit untuk melakukan tes terhadap kelas yang menggunakan Layanan Lokasi daripada menggunakan DI, jadi inilah mengapa Layanan Lokasi akhirnya menjadi pengecualian daripada aturan. Saya konsisten dalam penggunaannya, jadi tidak sulit untuk mengingat jenis tes yang harus saya tulis.

Beberapa telah mengemukakan kekhawatiran bahwa DI cenderung mengacaukan konstruktor. Saya tidak merasa ini adalah masalah, tetapi jika Anda merasa seperti ini, ada sejumlah alternatif yang menggunakan DI, tetapi hindari parameter konstruktor. Berikut ini adalah daftar metode DI Ninject: http://ninject.codeplex.com/wikipage?title=Injection%20Patterns

Anda akan menemukan bahwa sebagian besar kontainer Inversion of Control memiliki fitur yang sama dengan Ninject. Saya memilih untuk menunjukkan Ninject karena mereka memiliki sampel yang paling ringkas.

Semoga ini bermanfaat.

Edit: Agar jelas, saya menggunakan Unity dan Penunjuk Lokasi Umum. Saya memiliki contoh tunggal kontainer Persatuan saya untuk DI dan implementasi IServiceLocator saya hanyalah pembungkus di sekitar wadah Persatuan tunggal itu. Dengan cara ini saya tidak perlu melakukan pemetaan jenis apa pun dua kali atau semacamnya.

Saya juga tidak menemukan AOP sangat membantu melampaui pelacakan. Saya suka penebangan manual yang lebih baik hanya karena kejelasannya. Saya tahu bahwa kebanyakan kerangka kerja pencatatan AOP mampu keduanya, tetapi saya tidak membutuhkan yang pertama (roti dan mentega AOP) sebagian besar waktu. Ini hanya preferensi pribadi, tentu saja.


14
2018-04-21 13:34



Logger jelas merupakan layanan yang bergantung pada logika bisnis Anda, dan karenanya harus diperlakukan sebagai dependensi dengan cara yang sama seperti Anda IDependency. Suntikkan logger di konstruktor Anda.

catatan: meskipun AOP disebutkan sebagai itu cara untuk menyuntikkan penebangan Saya tidak setuju bahwa itu adalah solusi dalam kasus ini. AOP bekerja bagus untuk pelacakan eksekusi, tetapi tidak akan pernah menjadi solusi untuk penebangan sebagai bagian dari logika bisnis.


7
2018-04-21 13:50



Kami mengalihkan semua atribut Logging / Tracing to PostSharp (AOP framework). Yang perlu Anda lakukan untuk membuat pencatatan untuk metode adalah menambahkan atribut ke dalamnya.

Manfaat:

  • Mudah digunakan AOP
  • Bersih pemisahan masalah
  • Terjadi pada waktu kompilasi -> Dampak kinerja minimal

Periksa ini.


4
2018-04-21 11:53



Aturan kecil saya:

  • Jika berada di perpustakaan kelas, gunakan injeksi konstruktor atau injeksi properti dengan pola nol-objek.

  • Jika dalam aplikasi utama, gunakan pencari layanan (atau tunggal).

Saya menemukan ini berlaku cukup baik ketika menggunakan log4net. Anda tidak ingin perpustakaan kelas menjangkau hal-hal yang mungkin tidak ada di sana, tetapi dalam program aplikasi, Anda tahu bahwa logger akan ada di sana, dan pustaka seperti log4net sangat bergantung pada pola layanan-lokasi.

Saya cenderung menganggap penebangan sebagai sesuatu yang cukup statis sehingga tidak benar-benar membutuhkan DI. Sangat tidak mungkin saya akan pernah mengubah pelaksanaan penebangan dalam aplikasi, terutama karena setiap kerangka kerja penebangan di luar sana sangat fleksibel dan mudah diperluas. Ini lebih penting di perpustakaan kelas ketika perpustakaan Anda mungkin perlu digunakan oleh beberapa aplikasi yang sudah menggunakan penebang yang berbeda.

YMMV, tentu saja. DI sangat bagus tapi itu tidak berarti semuanya harus DIBEDAKAN.


4
2018-04-21 13:51



Anda dapat memperoleh jenis lain mis. LoggableBusinessObject yang mengambil logger di konstruktornya. Ini berarti Anda hanya meneruskan logger untuk objek yang akan menggunakannya:

public class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)   
    {   
        _dependency = dependency;   
    }   

    public virtual string DoSomething(string input)   
    {   
        // Process input   
        var info = _dependency.GetInfo();   
        var result = PerformInterestingStuff(input, info);   
        return result;   
    }   
}

public class LoggableBusinessObject : MyBusinessObject
{
    private ILogger _logger;

    public LoggableBusinessObject(ILogger logger, IDependency dependency)
        : base(dependency)
    {
        _logger = logger;
    }

    public override string DoSomething(string input)
    {
        string result = base.DoSomething(input);
        if (result == "SomethingWeNeedToLog")
        {
             _logger.Log(result);
        }
    }
}

3
2018-04-21 12:22



Mungkin ini akan sedikit offtopic, tapi mengapa kita perlu menginjeksi logger sama sekali, ketika kita bisa mengetik di awal kelas:

Logger logger = LogManager.GetLogger("MyClassName");

Logger tidak berubah selama pengembangan dan kemudian selama pemeliharaan. Pembebas modern sangat mudah disesuaikan, jadi argumen

bagaimana jika saya ingin mengganti logger teks dengan database?

dilewatkan.

Saya tidak meniadakan menggunakan suntikan ketergantungan, saya hanya ingin tahu tentang pikiran Anda.


2
2017-10-07 14:11



Saya lebih suka Singleton Service.

Ketergantungan injeksi akan mengacaukan konstruktor.

Jika Anda dapat menggunakan AOP, itu akan menjadi yang terbaik.


1
2018-04-21 11:53



DI akan bekerja dengan baik di sini. Hal lain yang harus dilihat adalah AOP.


0
2018-04-21 11:52



Saya tidak akan merekomendasikan kedua pendekatan ini. Lebih baik menggunakan pemrograman berorientasi aspek. Logging adalah "halo dunia" dari AOP.


0
2018-04-21 11:52