Subbab 5 / 9

Enkapsulasi (Encapsulation)

Belajar memahami mengapa data perlu dilindungi, bagaimana menerapkan enkapsulasi menggunakan properties, dan kapan menggunakannya dalam proyek nyata.

Tujuan pembelajaran

Setelah mempelajari materi ini, kamu diharapkan mampu:

  • Memahami konsep enkapsulasi melalui analogi sehari-hari.
  • Menjelaskan masalah ketika field dapat diubah secara bebas.
  • Menggunakan private, public, dan properties di C#.
  • Membuat validasi data menggunakan set.
  • Menerapkan enkapsulasi pada studi kasus sederhana.



1. Analogi dunia nyata

Mesin ATM: saldo tidak boleh diubah sembarangan

gambar atm
gambar atm

Bayangkan kamu memiliki rekening bank dengan saldo Rp500.000.

Ketika ingin mengambil uang, kamu menggunakan ATM. Kamu memasukkan PIN, memilih jumlah uang, lalu ATM memproses transaksi.

Kamu tidak bisa langsung membuka sistem internal ATM dan mengganti saldo menjadi Rp10.000.000 hanya dengan mengetik angka.

Mengapa?

Karena sistem ATM memiliki aturan:

  1. Saldo disimpan di dalam sistem dan tidak bisa diakses sembarangan.
  2. Pengguna hanya bisa melakukan operasi yang disediakan, seperti setor uang atau tarik uang.
  3. Sistem memeriksa apakah saldo mencukupi sebelum uang ditarik.

Hubungannya dengan OOP

Dunia nyata

C#

Saldo rekening

Field atau data dalam class

Sistem internal ATM

Data yang disembunyikan (private)

Tombol tarik/setor tunai

Method atau property yang dapat diakses

Validasi saldo

Logika bisnis di dalam class

Inti enkapsulasi:

Enkapsulasi adalah prinsip OOP yang menggabungkan data dan perilaku dalam sebuah class, sekaligus membatasi akses langsung terhadap data tersebut agar hanya dapat digunakan melalui aturan yang ditentukan.

Jadi, enkapsulasi bukan sekadar membuat field menjadi private. Tujuan utamanya adalah menjaga agar data tetap valid dan perubahan terhadapnya dapat dikontrol.


2. Masalah tanpa enkapsulasi (Kode Sebelum)

Mari kita buat simulasi rekening bank sederhana.

Contoh kode C# tanpa enkapsulasi

csharp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;

class RekeningBank
{
    public string NamaPemilik;
    public decimal Saldo;
}

class Program
{
    static void Main()
    {
        RekeningBank rekening = new RekeningBank();

        rekening.NamaPemilik = "Budi";
        rekening.Saldo = 500000;

        Console.WriteLine($"Saldo awal: {rekening.Saldo}");

        // Class lain dapat mengubah saldo secara bebas
        rekening.Saldo = -1000000;

        Console.WriteLine($"Saldo akhir: {rekening.Saldo}");
    }
}

Output

plaintext
1
2
Saldo awal: 500000
Saldo akhir: -1000000

Secara teknis, program tersebut dapat berjalan. Namun, secara logika bisnis, saldo rekening menjadi tidak masuk akal.

Apa masalahnya?

1. Data dapat diubah sembarangan

csharp
1
rekening.Saldo = -1000000;

Class Program dapat langsung mengganti nilai saldo tanpa meminta izin atau mengikuti aturan tertentu.

2. Tidak ada validasi

Saldo seharusnya tidak boleh negatif dalam simulasi rekening sederhana ini. Namun, class RekeningBank tidak memiliki mekanisme untuk mencegahnya.

3. Class lain terlalu mengetahui detail internal

Class lain dapat memanipulasi data rekening secara langsung. Jika aturan saldo berubah, kita harus mencari semua bagian kode yang mungkin mengubah field tersebut.

Gambaran masalah

Catatan: public bukan berarti selalu buruk. Field atau property public berguna ketika data memang boleh diakses. Masalahnya adalah ketika data penting dapat diubah tanpa kontrol.


3. Solusi dengan enkapsulasi (Kode Sesudah)

Sekarang kita perbaiki class RekeningBank agar saldo tidak bisa diubah secara langsung oleh class lain.

Langkah 1 — Gunakan access modifiers

Access modifier menentukan siapa yang dapat mengakses anggota sebuah class.

Modifier

Akses

public

Dapat diakses dari luar class

private

Hanya dapat diakses di dalam class itu sendiri

Contoh

csharp
1
2
3
4
5
6
7
8
9
class RekeningBank
{
    private decimal saldo;

    public void TampilkanSaldo()
    {
        Console.WriteLine(saldo);
    }
}

Di sini:

  • saldo bersifat private.
  • Class Program tidak bisa mengubah saldo secara langsung.
  • Method TampilkanSaldo() dapat digunakan untuk membaca saldo.

Jika kita menulis:

csharp
1
rekening.saldo = -1000000;

Maka akan muncul error karena saldo bersifat private.



Langkah 2 — Gunakan Properties C#

Di C#, cara modern untuk mengontrol akses data adalah menggunakan property.

Property terlihat seperti variabel ketika digunakan, tetapi dapat memiliki logika saat data dibaca atau diubah.

Struktur property

csharp
1
2
3
4
5
public decimal Saldo
{
    get { return saldo; }
    set { saldo = value; }
}

Penjelasan:

Bagian

Fungsi

public

Property bisa diakses dari luar class

decimal

Tipe data saldo

Saldo

Nama property

get

Mengambil nilai

set

Mengubah nilai

value

Nilai baru yang dikirim ke property

Versi modern C#

C# juga mendukung sintaks yang lebih ringkas:

csharp
1
2
3
4
5
public decimal Saldo
{
    get;
    set;
}

Namun, jika kita ingin melakukan validasi, kita perlu menambahkan logika di dalam set.


Langkah 3 — Enkapsulasi dengan validasi saldo

Berikut contoh class rekening yang sudah diperbaiki.

Kode C# lengkap

csharp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
using System;

class RekeningBank
{
    // Field private: tidak bisa diakses langsung dari luar
    private decimal saldo;

    public string NamaPemilik { get; set; }

    public decimal Saldo
    {
        get
        {
            return saldo;
        }
        private set
        {
            if (value >= 0)
            {
                saldo = value;
            }
            else
            {
                Console.WriteLine("Saldo tidak boleh negatif!");
            }
        }
    }

    public RekeningBank(string namaPemilik, decimal saldoAwal)
    {
        NamaPemilik = namaPemilik;

        if (saldoAwal >= 0)
        {
            saldo = saldoAwal;
        }
        else
        {
            throw new ArgumentException(
                "Saldo awal tidak boleh negatif."
            );
        }
    }

    public void Setor(decimal jumlah)
    {
        if (jumlah > 0)
        {
            Saldo += jumlah;
            Console.WriteLine(
                $"Setor berhasil: {jumlah}"
            );
        }
        else
        {
            Console.WriteLine(
                "Jumlah setor harus lebih dari 0."
            );
        }
    }

    public void Tarik(decimal jumlah)
    {
        if (jumlah <= 0)
        {
            Console.WriteLine(
                "Jumlah tarik harus lebih dari 0."
            );
        }
        else if (jumlah > Saldo)
        {
            Console.WriteLine(
                "Saldo tidak mencukupi."
            );
        }
        else
        {
            Saldo -= jumlah;
            Console.WriteLine(
                $"Tarik berhasil: {jumlah}"
            );
        }
    }
}

class Program
{
    static void Main()
    {
        RekeningBank rekening =
            new RekeningBank("Budi", 500000);

        Console.WriteLine(
            $"Pemilik: {rekening.NamaPemilik}"
        );

        Console.WriteLine(
            $"Saldo awal: {rekening.Saldo}"
        );

        rekening.Setor(200000);

        rekening.Tarik(100000);

        Console.WriteLine(
            $"Saldo akhir: {rekening.Saldo}"
        );

        // Tidak diperbolehkan:
        // rekening.Saldo = -1000000;
    }
}

Output

plaintext
1
2
3
4
5
Pemilik: Budi
Saldo awal: 500000
Setor berhasil: 200000
Tarik berhasil: 100000
Saldo akhir: 600000

Bedah kode: bagian penting

A. Field private

csharp
1
private decimal saldo;

Field saldo hanya bisa diakses langsung dari dalam class RekeningBank.

Class Program tidak dapat melakukan:

csharp
1
rekening.saldo = -1000000;

Ini adalah pembatasan akses terhadap data internal.

B. Property dengan private set


csharp
1
2
3
4
5
public decimal Saldo
{
    get;
    private set;
}

Dalam contoh lengkap, property ditulis dengan validasi:

csharp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public decimal Saldo
{
    get
    {
        return saldo;
    }
    private set
    {
        if (value >= 0)
        {
            saldo = value;
        }
    }
}

Artinya:

  • public get → saldo dapat dibaca dari luar class.
  • private set → saldo hanya dapat diubah melalui kode di dalam class.
  • Validasi value >= 0 → nilai negatif ditolak.

C. Method Setor() dan Tarik()

csharp
1
2
3
4
5
6
7
public void Setor(decimal jumlah)
{
    if (jumlah > 0)
    {
        Saldo += jumlah;
    }
}
csharp
1
2
3
4
5
6
7
public void Tarik(decimal jumlah)
{
    if (jumlah > 0 && jumlah <= Saldo)
    {
        Saldo -= jumlah;
    }
}

Class dari luar tidak mengubah saldo secara langsung. Mereka meminta class rekening melakukan operasi melalui method yang disediakan.


Visualisasi alur enkapsulasi


Perbandingan kode sebelum dan sesudah

Sebelum

Sesudah

public decimal Saldo;

private decimal saldo;

Bisa diubah bebas

Tidak bisa diubah langsung

Tidak ada validasi

Ada validasi

Class lain memanipulasi data

Class mengatur perubahan melalui method

Risiko data tidak valid

Data lebih terkontrol

4. Kesimpulan

Tiga manfaat utama enkapsulasi

1. Melindungi data

Dengan private, data penting tidak dapat diubah sembarangan dari luar class.

Contoh: saldo rekening tidak dapat langsung diisi angka negatif.

2. Menjaga validitas data

Dengan property atau method yang memiliki validasi, class dapat memastikan data sesuai aturan.

Contoh:

csharp
1
2
3
4
if (value >= 0)
{
    saldo = value;
}

3. Mempermudah pemeliharaan kode

Aturan perubahan data berada di dalam class yang bertanggung jawab.

Jika aturan saldo berubah, kita dapat memperbaiki logika di RekeningBank tanpa harus mengubah semua class yang menggunakan rekening.