Injection Konstruktor & Interface
Terapkan injection konstruktor dengan desain berbasis interface untuk memisahkan komponen dan memungkinkan pengujian unit.
Injection Konstruktor & Interface adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.
Dasar-Dasar Injeksi Konstruktor
Injeksi konstruktor adalah pola DI yang paling umum. Kelas mendeklarasikan dependensinya sebagai parameter konstruktor, lalu wadah menyediakannya saat instans dibuat.
Dengan demikian, dependensi menjadi jelas, wajib, dan terlihat.
Mendefinisikan Antarmuka
Mulailah dengan antarmuka yang mendefinisikan kontrak. Dengan cara ini, berbagai implementasi (nyata, tiruan, dalam memori) dapat saling menggantikan tanpa mengubah kode yang bergantung padanya.
public interface IProductRepository
{
Task<Product?> GetByIdAsync(int id);
Task<IEnumerable<Product>> GetAllAsync();
Task AddAsync(Product product);
}Mengimplementasikan Antarmuka
Implementasi konkret menangani pekerjaan sebenarnya — pemanggilan basis data, permintaan HTTP, dan sebagainya. Pemakai layanan tidak perlu mengetahui implementasi mana yang diterimanya.
public class SqlProductRepository : IProductRepository
{
private readonly AppDbContext _db;
public SqlProductRepository(AppDbContext db) => _db = db;
public async Task<Product?> GetByIdAsync(int id)
=> await _db.Products.FindAsync(id);
public async Task<IEnumerable<Product>> GetAllAsync()
=> await _db.Products.ToListAsync();
public async Task AddAsync(Product product)
{
_db.Products.Add(product);
await _db.SaveChangesAsync();
}
}Menggunakan melalui Konstruktor
Lapisan layanan menerima IProductRepository sebagai parameter konstruktor. Lapisan ini tidak pernah mengetahui SqlProductRepository — hanya kontrak antarmukanya.
public class ProductService
{
private readonly IProductRepository _repo;
private readonly ILogger<ProductService> _logger;
public ProductService(
IProductRepository repo,
ILogger<ProductService> logger)
{
_repo = repo;
_logger = logger;
}
public async Task<Product?> GetProductAsync(int id)
{
_logger.LogInformation("Fetching product {Id}", id);
return await _repo.GetByIdAsync(id);
}
}Mendaftarkan Rantai
Daftarkan setiap layanan dalam rantai. Wadah menyelesaikan seluruh grafik dependensi secara otomatis — ProductService → IProductRepository → AppDbContext.
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlite("Data Source=app.db"));
builder.Services.AddScoped<IProductRepository, SqlProductRepository>();
builder.Services.AddScoped<ProductService>();Pengujian dengan Tiruan
Karena dependensi disuntikkan melalui antarmuka, pengujian unit dapat meneruskan tiruan atau objek palsu tanpa menyentuh basis data. Ini adalah salah satu manfaat terbesar DI.
// Using NSubstitute or Moq in a unit test
var mockRepo = Substitute.For<IProductRepository>();
mockRepo.GetByIdAsync(1).Returns(new Product { Id = 1, Name = "Widget" });
var logger = Substitute.For<ILogger<ProductService>>();
var svc = new ProductService(mockRepo, logger);
var result = await svc.GetProductAsync(1);
Assert.Equal("Widget", result?.Name);Beberapa Parameter Konstruktor
Sebuah kelas dapat memiliki banyak parameter konstruktor. Wadah akan menyelesaikan semuanya selama setiap parameter telah didaftarkan. Jaga agar konstruktor tetap berfokus — terlalu banyak parameter merupakan indikasi bahwa kelas memiliki terlalu banyak tanggung jawab.
public class OrderService
{
public OrderService(
IOrderRepository orders,
IProductRepository products,
IEmailSender email,
ILogger<OrderService> logger)
{
// all injected by DI container
}
}Menghindari Antipola Pencari Layanan
JANGAN menyuntikkan IServiceProvider lalu memanggil GetService di dalam metode bisnis. Cara ini menyembunyikan dependensi dan menyulitkan pengujian. Utamakan injeksi konstruktor agar kode tetap jelas dan mudah diuji.
// BAD
public void Process(IServiceProvider sp)
{
var repo = sp.GetService<IProductRepository>(); // hidden dep!
}
// GOOD
public class Processor
{
private readonly IProductRepository _repo;
public Processor(IProductRepository repo) => _repo = repo;
}Sintaks Konstruktor Utama (C# 12)
C# 12 memperkenalkan konstruktor utama untuk semua jenis kelas, sehingga Anda dapat mendeklarasikan parameter langsung pada deklarasi kelas untuk kode DI yang lebih ringkas.
// C# 12 primary constructor
public class ProductService(
IProductRepository repo,
ILogger<ProductService> logger)
{
public async Task<Product?> GetAsync(int id)
{
logger.LogInformation("Getting {Id}", id);
return await repo.GetByIdAsync(id);
}
}Menukar Implementasi
Salah satu keunggulan utama DI berbasis antarmuka adalah Anda dapat menukar implementasi hanya dalam satu baris tanpa mengubah kode pemakainya. Ini berguna untuk mengganti basis data, penyedia surat, atau penanda fitur.
// Switch from SQL to in-memory for integration tests
if (environment.IsEnvironment("Test"))
builder.Services.AddScoped<IProductRepository, InMemoryProductRepository>();
else
builder.Services.AddScoped<IProductRepository, SqlProductRepository>();Dunia Nyata: Pengontrol dengan DI
Pengontrol ASP.NET Core secara bawaan menggunakan injeksi konstruktor. Kerangka kerja menyelesaikan semua parameter lalu meneruskannya.
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
private readonly ProductService _svc;
public ProductsController(ProductService svc) => _svc = svc;
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var product = await _svc.GetProductAsync(id);
return product is null ? NotFound() : Ok(product);
}
}Pemeriksaan Singkat
Apa manfaat utama memprogram berdasarkan antarmuka saat menggunakan DI?
Rangkuman: Injeksi Konstruktor & Antarmuka
Hal-hal penting:
- Deklarasikan dependensi sebagai parameter konstruktor — wadah yang menyediakannya
- Definisikan antarmuka untuk kontrak layanan; suntikkan antarmukanya, bukan jenis konkretnya
- Antarmuka memungkinkan pembuatan tiruan dengan mudah dalam pengujian unit dan memudahkan penggantian implementasi
- Konstruktor utama C# 12 mengurangi kode berulang pada kelas yang banyak menggunakan DI
- Hindari antipola pencari layanan — pertahankan dependensi agar tetap jelas
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Injection Konstruktor & Interface” gratis?
Ya — teks lengkap “Injection Konstruktor & Interface” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Injection Konstruktor & Interface”?
Terapkan injection konstruktor dengan desain berbasis interface untuk memisahkan komponen dan memungkinkan pengujian unit. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai C# Academy?
Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Injection Konstruktor & Interface” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?
Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Dasar-Dasar Kontainer DI
- Masa Hidup Layanan: Transient, Scoped, Singleton
- Injection Konstruktor & Interface
- Pola Factory & Options