Delegate dan interface sama-sama memungkinkan perilaku ditukar saat runtime. Diskon potongan harga, misalnya, dapat dimodelkan sebagai delegate Func<int, int> maupun sebagai interface IStrategiDiskon. Keduanya menghasilkan output yang identik, sehingga pertanyaannya bukan soal benar atau salah, melainkan soal bentuk masalah yang sedang kita tangani.

Panduan Memilih #

AspekDelegateInterface
Jumlah membersatu methodsekumpulan member
Statetidak membawa state sendiriimplementer dapat memiliki field
Kegunaan khascallback, event, strategi satu langkahkontrak multi member, plugin, dependency injection
Deklarasitanpa deklarasi tipe baru (Action, Func)butuh class atau struct implementer

Aturan praktisnya: satu operasi tertukar-ganti memakai delegate; kelompok operasi yang saling terkait dan butuh state memakai interface.

Perbedaan paling menentukan ada pada state dan jumlah member. Delegate tidak menyimpan data di dalam dirinya; state yang dibutuhkan harus ditangkap lewat closure. Interface, sebaliknya, ditemani class implementer yang bebas menyimpan field, sehingga cocok untuk strategi yang membutuhkan konfigurasi maupun riwayat pemakaian.

Contoh Perbandingan #

csharp
interface IStrategiDiskon
{
    int Hitung(int total);
}

class DiskonPersen : IStrategiDiskon
{
    private readonly int _persen;

    public DiskonPersen(int persen) => _persen = persen;

    public int Hitung(int total) => total * _persen / 100;
}

static int DiskonMember(int total) => total * 10 / 100;

int total = 200000;

IStrategiDiskon strategiClass = new DiskonPersen(10);
Func<int, int> strategiDelegate = DiskonMember;

Console.WriteLine($"Interface: potongan {strategiClass.Hitung(total)}");
Console.WriteLine($"Delegate : potongan {strategiDelegate(total)}");

Output yang Dihasilkan:

text
Interface: potongan 20000
Delegate : potongan 20000

Bedah Kode Baris per Baris #

Mari kita telaah kode di atas:

  1. Baris 1-4: Interface IStrategiDiskon menjanjikan satu method Hitung. Jika kebutuhan berkembang, misalnya menambah deskripsi dan batas periode, interface menampungnya tanpa mengubah pemanggil.
  2. Baris 6-13: DiskonPersen menyimpan state _persen di field. State seperti ini tidak dimiliki delegate.
  3. Baris 15: DiskonMember adalah method sederhana yang langsung ditugaskan ke Func<int, int> tanpa deklarasi tipe apa pun.
  4. Baris 20-23: Kedua strategi menghasilkan potongan 20000 dari total 200000, membuktikan keduanya setara untuk kasus satu operasi ini.

Angka 20000 pada kedua baris output sengaja identik: untuk satu operasi murni, delegate dan interface benar-benar setara. Keputusan desain baru bermakna ketika kebutuhan berkembang, dan tabel di atas memberi arah pergeserannya.