Konsep Dasar OOP Python: Enkapsulasi, Inheritance, dan Polimorfisme

belajar konsep dasar oop di python

KakaKiky - Pemrograman berorientasi objek atau Object-Oriented Programming (OOP) adalah paradigma pemrograman yang menggunakan "objek" untuk mendesain aplikasi dan program. OOP mengizinkan pengembang untuk berpikir tentang perangkat lunak sebagai kumpulan objek yang saling berinteraksi. Ada tiga konsep utama dalam OOP yang esensial untuk dipahami, yaitu: Enkapsulasi, Inheritance (Pewarisan), dan Polimorfisme. Pada materi Python untuk pemula kali ini kita akan membahas semuanya lengkap dengan contoh kode dan penerapannya.

Enkapsulasi

Enkapsulasi adalah salah satu pilar fundamental dari Pemrograman Berorientasi Objek (OOP). Konsep ini mengacu pada pembungkusan data (atribut) dan fungsi (metode) yang beroperasi pada data tersebut ke dalam sebuah unit tunggal atau objek. Hal ini dilakukan untuk:

  • Melindungi integritas data dengan mencegah akses langsung ke atribut internal.
  • Menyembunyikan kompleksitas dan detail implementasi dari pengguna.
  • Dengan enkapsulasi, kita dapat membatasi akses langsung ke atribut objek dan hanya memungkinkan manipulasi melalui metode tertentu. Ini dikenal sebagai data hiding.

Contoh Kode Enkapsulasi

Misalkan kita ingin membuat sebuah kelas BankAccount:

class BankAccount:
    
    def __init__(self, balance=0):
        # atribut private, tidak dapat diakses langsung dari luar kelas
        self.__balance = balance

    # metode untuk menyetor uang
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return f"Berhasil menyetor {amount}. Saldo sekarang: {self.__balance}"
        else:
            return "Jumlah tidak valid!"

    # metode untuk menarik uang
    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            return f"Berhasil menarik {amount}. Saldo sekarang: {self.__balance}"
        else:
            return "Penarikan tidak valid atau saldo tidak cukup!"

    # metode untuk mengecek saldo
    def check_balance(self):
        return f"Saldo anda: {self.__balance}"

Penerapan:

# Membuat objek dari kelas BankAccount
account = BankAccount(1000)

# Menyetor uang
print(account.deposit(500))  # "Berhasil menyetor 500. Saldo sekarang: 1500"

# Mengecek saldo
print(account.check_balance())  # "Saldo anda: 1500"

# Menarik uang
print(account.withdraw(200))  # "Berhasil menarik 200. Saldo sekarang: 1300"

# Coba akses saldo langsung (akan menghasilkan error karena __balance adalah private)
# print(account.__balance)  # AttributeError

Dalam contoh di atas, kita telah "menyembunyikan" atribut __balance dari akses langsung. Hal ini dilakukan dengan menambahkan dua garis bawah di depan nama atribut (__balance). Sebagai gantinya, kita menyediakan metode deposit(), withdraw(), dan check_balance() untuk berinteraksi dengan saldo.

Dengan enkapsulasi, kita memastikan bahwa saldo hanya dapat diubah dengan cara yang sesuai dan aman, seperti melalui metode deposit() dan withdraw(), sehingga mencegah perubahan yang tidak diinginkan atau tidak sah pada saldo.

Inheritance (Pewarisan)

Inheritance atau pewarisan dalam OOP memungkinkan sebuah kelas untuk mewarisi atribut dan metode dari kelas lain. Kelas yang diwarisi disebut sebagai "kelas induk" atau "kelas dasar", sedangkan kelas yang mewarisi disebut sebagai "kelas anak" atau "kelas turunan".

Manfaat utama dari pewarisan adalah:

  • Penggunaan Ulang Kode (Reusability): kamu dapat mewarisi atribut dan metode dari kelas induk tanpa perlu menulis ulang kode tersebut di kelas anak.
  • Organisasi Kode: Pewarisan memungkinkan kamu untuk membuat struktur hierarki kelas yang menggambarkan hubungan antara kelas-kelas berdasarkan tingkat generalitas atau spesifiknya.
  • Extensibility: kamu dapat menambahkan atau memodifikasi atribut dan metode di kelas anak tanpa mengganggu kelas induk.

Contoh Kode Python untuk Inheritance

Mari kita ambil contoh sederhana tentang hubungan antara kelas Kendaraan (kelas induk) dan kelas Mobil dan Sepeda (kelas anak).

# Kelas Induk
class Kendaraan:
    def __init__(self, merk, warna):
        self.merk = merk
        self.warna = warna

    def tampilkan_informasi(self):
        return f"Kendaraan ini bermerk {self.merk} dengan warna {self.warna}."

# Kelas Anak (Mobil)
class Mobil(Kendaraan):
    def __init__(self, merk, warna, tipe):
        super().__init__(merk, warna)  # Memanggil konstruktor dari kelas induk
        self.tipe = tipe

    def tampilkan_informasi(self):
        return f"Mobil ini bermerk {self.merk}, berwarna {self.warna}, dan bertipe {self.tipe}."

# Kelas Anak (Sepeda)
class Sepeda(Kendaraan):
    def __init__(self, merk, warna, jenis):
        super().__init__(merk, warna)
        self.jenis = jenis

    def tampilkan_informasi(self):
        return f"Sepeda ini bermerk {self.merk}, berwarna {self.warna}, dan berjenis {self.jenis}."

# Membuat objek dari kelas anak
mobil1 = Mobil("Toyota", "Hitam", "SUV")
print(mobil1.tampilkan_informasi())

sepeda1 = Sepeda("Polygon", "Merah", "Gunung")
print(sepeda1.tampilkan_informasi())

Dalam contoh di atas, kita dapat melihat bagaimana kelas Mobil dan Sepeda mewarisi atribut dan metode dari kelas Kendaraan. Namun, mereka juga menambahkan atribut dan metode spesifik mereka sendiri. Metode tampilkan_informasi di kedua kelas anak menggantikan metode dengan nama yang sama di kelas induk, contoh dari konsep yang disebut "overriding".

Polimorfisme

Polimorfisme dalam pemrograman berorientasi objek mengacu pada kemampuan objek dari kelas berbeda untuk diakses melalui antarmuka yang sama. Konsep ini memungkinkan objek untuk didefinisikan dan diakses dengan cara yang sama, tanpa perlu tahu kelas aslinya. Polimorfisme membuat sistem lebih modular dan mudah diperluas.

Dua jenis utama polimorfisme

  • Polimorfisme Waktu Kompilasi (Compile-time Polymorphism): Ini juga dikenal sebagai overloading. Di Python, kamu tidak benar-benar melihat contoh ini karena Python tidak mendukung overloading fungsi atau metode. Namun, kamu bisa meng-overload operator.
  • Polimorfisme Waktu Eksekusi (Runtime Polymorphism): Ini adalah bentuk polimorfisme yang paling umum di Python dan terjadi ketika kamu memiliki metode dengan nama yang sama di kelas-kelas yang berbeda.

Contoh Polimorfisme dengan

Mari kita buat kelas Burung dan Ikan. Kedua kelas ini akan memiliki metode bergerak, tetapi perilaku dari metode ini akan berbeda untuk kedua kelas:

class Burung:
    def bergerak(self):
        return "Burung terbang di udara"

class Ikan:
    def bergerak(self):
        return "Ikan berenang di air"

def gerakan_makhluk(makhluk):
    print(makhluk.bergerak())

# Membuat objek dari kelas Burung dan Ikan
pelikan = Burung()
salmon = Ikan()

# Memanggil fungsi gerakan_makhluk
gerakan_makhluk(pelikan)  # Output: Burung terbang di udara
gerakan_makhluk(salmon)   # Output: Ikan berenang di air

Dalam contoh di atas, gerakan_makhluk menerima parameter makhluk yang bisa berupa objek dari kelas Burung atau Ikan. Ketika fungsi ini dipanggil, ia menjalankan metode bergerak yang sesuai dengan tipe objek yang diteruskan. Ini adalah contoh polimorfisme, di mana kode dapat bekerja dengan objek dari kelas yang berbeda melalui cara yang sama.

Penerapan Polimorfisme

  • Kemudahan dalam Manajemen Kode: Seperti yang kamu lihat pada contoh di atas, kita bisa menggunakan satu fungsi atau metode untuk berinteraksi dengan objek dari kelas yang berbeda. Hal ini membuat manajemen kode menjadi lebih mudah dan lebih terorganisir.
  • Fleksibilitas: Polimorfisme memungkinkan kita untuk menambahkan kelas baru tanpa perlu mengubah banyak kode. Misalnya, jika kamu ingin menambahkan kelas Kucing dengan metode bergerak yang berbeda, kamu hanya perlu menambahkan kelas tersebut tanpa mengubah fungsi gerakan_makhluk.
  • Dukungan untuk Ekstensibilitas: Karena polimorfisme memungkinkan kita untuk merancang satu antarmuka untuk berbagai kelas, memungkinkan kita untuk menambahkan lebih banyak kelas di masa depan dengan sedikit atau tanpa modifikasi pada kode yang ada.

Dengan memahami dan menerapkan polimorfisme, kamu bisa membuat aplikasi yang lebih modular, fleksibel, dan mudah diperluas.

Kesimpulan

OOP menyajikan paradigma pemrograman yang kuat dan fleksibel, dengan konsep-konsep seperti Enkapsulasi, Inheritance, dan Polimorfisme yang memungkinkan pengembang untuk menulis kode yang lebih terorganisir, modular, dan mudah dikelola. Dengan memahami konsep-konsep ini, kamu akan lebih siap untuk mengembangkan aplikasi yang efisien dan efektif.