Misalkan saya memiliki Service
yang menerima dependensi melalui konstruktor tetapi juga perlu diinisialisasi dengan data kustom (konteks) sebelum dapat digunakan:
public interface IService
{
void Initialize(Context context);
void DoSomething();
void DoOtherThing();
}
public class Service : IService
{
private readonly object dependency1;
private readonly object dependency2;
private readonly object dependency3;
public Service(
object dependency1,
object dependency2,
object dependency3)
{
this.dependency1 = dependency1 ?? throw new ArgumentNullException(nameof(dependency1));
this.dependency2 = dependency2 ?? throw new ArgumentNullException(nameof(dependency2));
this.dependency3 = dependency3 ?? throw new ArgumentNullException(nameof(dependency3));
}
public void Initialize(Context context)
{
// Initialize state based on context
// Heavy, long running operation
}
public void DoSomething()
{
// ...
}
public void DoOtherThing()
{
// ...
}
}
public class Context
{
public int Value1;
public string Value2;
public string Value3;
}
Sekarang - data konteks tidak diketahui sebelumnya jadi saya tidak bisa mendaftarkannya sebagai ketergantungan dan menggunakan DI untuk menyuntikkannya ke dalam layanan
Beginilah contoh klien terlihat seperti:
public class Client
{
private readonly IService service;
public Client(IService service)
{
this.service = service ?? throw new ArgumentNullException(nameof(service));
}
public void OnStartup()
{
service.Initialize(new Context
{
Value1 = 123,
Value2 = "my data",
Value3 = "abcd"
});
}
public void Execute()
{
service.DoSomething();
service.DoOtherThing();
}
}
Seperti yang Anda lihat - ada kopling temporal dan inisialisasi kode metode bau yang terlibat, karena saya pertama-tama harus memanggil service.Initialize
untuk dapat memanggil service.DoSomething
dan service.DoOtherThing
sesudahnya.
Apa pendekatan lain di mana saya bisa menghilangkan masalah ini?
Klarifikasi tambahan dari perilaku:
Setiap instance klien perlu memiliki instance layanan itu sendiri yang diinisialisasi dengan data konteks spesifik klien. Jadi, data konteks itu tidak statis atau diketahui sebelumnya sehingga tidak dapat disuntikkan oleh DI dalam konstruktor.
Service
memiliki dependensi selainContext
, yang tidak disediakan olehClient
, mereka dapat diberikan melalui DI untukServiceFactory
diteruskan keService
saatcreateService
dipanggil.ServiceBuilder partial = new ServiceBuilder().dependency1(dependency1_1).dependency2(dependency2_1).dependency3(dependency3_1);
dan dibiarkan dengan layanan pengaturan sebagian Anda, kemudian nantiService s = partial.context(context).build()
The
Initialize
Metode harus dihapus dariIService
antarmuka, karena ini adalah detail pelaksanaan. Alih-alih, tentukan kelas lain yang mengambil contoh konkret Layanan dan memanggil metode inisialisasi di dalamnya. Kemudian kelas baru ini mengimplementasikan antarmuka IService:Ini membuat kode klien tidak mengetahui prosedur inisialisasi, kecuali di mana
ContextDependentService
kelas diinisialisasi. Anda setidaknya membatasi bagian-bagian dari aplikasi Anda yang perlu tahu tentang prosedur inisialisasi yang miring ini.sumber
Menurut saya, Anda memiliki dua opsi di sini
misalnya.
misalnya.
Menyuntikkan pabrik tidak masalah jika Anda hanya ingin menghindari konteks lewat sebagai parameter. Katakan saja implementasi khusus ini membutuhkan konteks dan Anda ingin tidak menambahkannya ke Antarmuka
Tetapi Anda pada dasarnya memiliki masalah yang sama, bagaimana jika pabrik belum memiliki konteks yang sudah diinisialisasi.
sumber
Anda seharusnya tidak bergantung pada antarmuka Anda ke konteks db dan menginisialisasi metode. Anda dapat melakukannya di konstruktor kelas beton.
Dan, jawaban dari pertanyaan utama Anda adalah Injeksi Properti .
Dengan cara ini Anda dapat memanggil semua dependensi dengan Injeksi Properti . Tapi bisa jadi jumlahnya sangat banyak. Jika demikian, Anda bisa menggunakan Injeksi Konstruktor untuk mereka, tetapi Anda dapat mengatur konteks Anda dengan properti dengan memeriksa apakah itu nol.
sumber
Misko Hevery memiliki posting blog yang sangat membantu tentang kasus yang Anda hadapi. Anda berdua membutuhkan yang baru dan dapat disuntikkan untuk
Service
kelas Anda dan posting blog ini dapat membantu Anda.sumber