# Perwarisan, Pengkapsulan dan Polimorfism dalam OOP: Sebuah Pendekatan

# Revisi OOP

*Object-oriented programming* (OOP) adalah sebuah pendekatan dalam pengaturcaraan yang menjadikan **objek** sebagai rujukan akses kepada metod (fungsi) tertentu. Dalam Python, OOP diprogram menggunakan katakunci `Class`.

Dalam `Class`, anda boleh rangkumkan beberapa metod atau operasi yang mempunyai perkatainan antara satu sama lain. Misalanya jika kita mencipta `Class` operasi matematik, dalam `Class` tersebut seharusnua terdapat metod penambahan, penolakan, pembahagian dan lain-lain lagi, bergantung kepada pengaturcara itu sendiri. Anda juga boleh mencipta atribut (seperti pemboleh ubah jika diluar Class) yang dapat digunakan oleh metod `Class` tersebut.

Dalam membangunakan OOP, terdapat beberapa konsep atau pendekatan tertentu yang biasa dipraktikkan.

Antara pendekatan yang biasa digunakan adalah:

1.  Perwarisan (*Inheritance*)
    
2.  Pengkapsulan (*Encapsulation*)
    
3.  Polimorphism (*Polymorphism*)
    

> Nota:
> 
> Jika anda belum terbiasa dengan konsep OOP, penulis menyarankan anda untuk berkenalan dengan OOP dahulu sebelum meneruskan pembacaan artikel ini.

## Perwarisan

Seperti namanya, perwarisan boleh dianalogikan seperti ibubapa yang mewariskan genetik mereka pada si anak. 

Dalam konteks Python, terdapat Class ibubapa dan Class anak. 

Class anak akan mewarisi Class ibu bapa, seperti mana anak yang mewarisi ciri ibu bapanya.

![Free photos of Father](https://cdn.pixabay.com/photo/2012/03/04/01/01/father-22194_960_720.jpg align="left")

Mari kita lihat bagaimana caranya untuk menggunakan Perwarisan dalam Class.

```python
class Animal:
    def __init__(self, height, animal_type):
        self.size = height
        self.animal_type = animal_type

    def get_height(self):
        print(self.height)

    def get_animal_type(self):
        print(self.animal_type)

# perwarisan
class ExtendAnimal(Animal):
    def init(self, height, weight, animal_type, movement):
        self.height = height
        self.weight = weight
        self.animal_type = animal_type
        self.movement = movement
    def get_height_weight(self):
        self.get_height()
        print(self.weight) # extension
    def get_type_movement(self):
        self.get_animal_type()
        print(self.movement) # extension


fish = ExtendAnimal(5, 10, 'Amphibian', 'Swimming')
fish.get_height_weight()
fish.get_type_movement()
```

```python
Output:
5
10
Amphibian
Swimming
```

Contoh kod diatas adalah contoh perwarisan Class.

`Class` yang pertama iaitu `Animal` adalah `Class` yang memaparkan ciri haiwan iaitu `height` dan `animal_type`.

`Class` yang kedua iaitu `ExtendAnimal` telah mewarisi (`class ExtendAnimal(Animal)`) daripada Class yang pertama dan telah menambah keupayaan `Class` pertama jika dilihat pada metodnya.

Kita dapat melihat bagaimana Perwarisan dapat menambah lagi fungsi Class pada metod `get_height_weight()`yang mengeluarkan output `height`  yang diwariskan daripada `Class Animal`. Metod ini juga adalah *extension* daripada metod `get_height` daripada class `Animal` yang mana ia mengoutput `weight` dalam masa yang sama.

Dengan mewarisi Class ibubapa, Class anak mempunyai keupayaan tertentu hasil daripada perwarisan tadi. Antaranya;

> 1.  Class anak mempunyai ciri yang sama daripada Class ibu bapa.
>     
> 2.  Class anak boleh ditambah kemampuan kegunaan metodnya.
>     
> 3.  Class anak boleh dikemasikini (\**update*\*) tanpa mengganggu kod asal daripada Class ibubapa.
>     
> 4.  Atribut dan method dalam Class anak boleh mengatasi (\**override\**) Class ibubapa.
>     
> 5.  Class ibubapa boleh berkongsi atribut kepada Class anak.
>     
> 6.  Mencipta heirarki Class berturutan daripada Class ibubapa kepada Class anak.
>     

Jadi apa kebaikan jika kita menggunakan pendekatan ini?

> 1.  Pengaturcara mampu menambah baik kod asal tanpa mengubahsuai struktur kod tersebut.
>     
> 2.  Class anak boleh mewarisi keseluruhan ciri Class ibubapa, atau mewarisi sebahagian sahaja daripada ciri Class ibubapa. Ini memberi kawalan yang baik kepada pengaturcara untuk menambah baik Class ibubapa dengan had tertentu.
>     

## Pengkapsulan

Pengkapsulan adalah sebuah pendekatan dimana metod-metod dirangkumkan dalam satu unit.

> Penggunaan Class dalam Python itu sendiri adalah sebuah pengkapsulan.

![Free photos of Capsules](https://cdn.pixabay.com/photo/2015/12/06/18/28/capsules-1079838__340.jpg align="center")

Pengkapsulan dapat menyekat akses kepada atribut dan metod dalam Class (*underscore variable* dan penggunaan metod yang hanya diketahui oleh pencipta kod tersebut) yang dapat mengelakkan daripada data diubahsuai daripada kod atau pengguna luar.

Andaikan anda ingin mencipta sebuah Class yang mengandungi maklumat rahsia ejen peribadi. Tentu sahaja anda tidak mahu informasi ini dimanipulasi atau diubahsuai oleh kod atau pengguna luar.

Maka untuk menjadikan atribut tersebut peribadi, gunakan 2 *underscore* seperti kod dibawah;

```python
class ClassifiedInfo:
    def init(self, name, height, weight, country, gender):
        self.name = name
        self.__height = height
        self.__weight = weight
        self.__country = country
        self.__gender = gender
    def get_agent_information(self):
        print(f'{self.name} information:\
        \nGender: {self.__gender}, \
        \nCountry: {self.__country},')
    def get_agent_height(self):
        print(f'Height: {self.__height}')

agent_1 = ClassifiedInfo("Jack", 178, 89, "Brazil", "Male")\
agent_1.get_agent_information()
agent_1.__height
```

```python
Output:

Jack information:
Gender: Male,
Country: Brazil,
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[34], line 20
17 agent_1 = ClassifiedInfo("Jack", 78, 189, "Brazil", "Male")\
19 agent_1.get_agent_information()
---> 20 agent_1.__height
AttributeError: 'ClassifiedInfo' object has no attribute '__height'
```

Jika diperhatikan, output daripada `agent_1.__height` adalah <mark>ralat atribut</mark>. Ini bermakna maklumat `height` tidak mampu diakses sewenenang-wenangnya.

Dengan menggunakan dua *underscore*, ia boleh melindungi atribut dalam Class daripada dimanipulasi oleh kod atau pengguna luar.

Jadi bagaimana caranya untuk mengakses atribut peribadi ini? Dengan mencipta metod yang dapat diaksesnya. Dalam kod diatas, penulis telah mencipta sebuah metod `get_agent_height` yang mana metod ini akan mengeluarkan output maklumat ketinggian agent ini.

Ini bermakna, pengguna luar tidak berupaya untuk mengakses atribut peribadi dalam sesebuah kod, dan hanya pembangun kod sahaja yang mampu mengakses data tersebut dengan menggunakan metod yang dia ciptakan.

Dalam kod diatas, penulis telah mencipta metod `get_agent_height()` untuk mengakses maklumat atribut `height` .

```python
# mengakses atribut peribadi
agent_1.get_agent_height()
```

```python
Output:

Height: 178
```

Maklumat `height` telah **berjaya** diakses.

Kebaikan menggunakan pengkapsulan adalah;

> 1.  Punca ralat dapat dikenalpasti dengan merujuk nama Class dan metod.
>     
> 2.  Pengaturcara dapat melindungi data tertentu daripada diubahsuai oleh pengguna luar.
>     

## Polimorfism

Polimorfism berasal daripada bahasa Greek, bermakna sesuatu yang wujud dalam bentuk (morfo) yang pelbagai (poli).

![Free photos of Acropolis](https://cdn.pixabay.com/photo/2017/09/07/16/50/acropolis-2725918__340.jpg align="center")

Dalam konteks OOP, Class akan yang sama akan dicipta dalam pelbagai bentuk.

Konsep polimorfism telah digunakapakai secara meluas dalam pengaturcaraan. Antara contoh polimorfism dalam Python adalah simbol tambah (+) itu sendiri.

```python
# penambahan nombor
value_a = 12
value_b = 5
print(a+b)
# penggabungan string
string_1 = “Hello”
space = “ “
string_2 = “World!”
print( string_1 + space + string_2)
```

```python
Output:
17
Hello World!
```

Dalam Python, jika simbol tambah digunakan pada nombor (*interger*), ia akan menambahkan nilai nombor tersebut. Manakala jika digunakan pada perkataan (*string*), perkataan tersebut akan digabungkan. Maka simbol tambah ini bergantung kepada input apa yang diberikan. Ia simbol yang sama, tapi boleh wujud dalam kegunaan berbeza.

Mari kita lihat bagaimana anda boleh mengaplikasikan polimorfism pada Class dalam Python.

```python
class Jack:
def init(self, age, gender, address):
    self.age = age
    self.gender  = gender
    self.address = address

    def get_age(self):
        print(f'Age: {self.age}')

    def get_gender(self):
        print(f'Gender: {self.gender}')

    def get_address(self):
        print(f'Address: {self.address}')

class Jenny:
    def __init__(self, age, gender, address):
        self.age = age
        self.gender  = gender
        self.address = address

    def get_age(self):
        print(f'Age: {self.age}')

    def get_gender(self):
        print(f'Gender: {self.gender}')

    def get_address(self):
        print(f'Address: {self.address}')

jack = Jack(19, 'male','USA')
jenny = Jenny(21, 'female', 'Colombia')
```

Dalam kod diatas, `Class Jack` and `Jenny` mempunyai struktur yang sama; dengan nama metod yang sama tetapi bentuk (nama Class) yang berbeza. Ini adalah konsep polimorfism.

Daripada objek diatas, anda boleh menggunakan kesemua metod untuk mendapatkan output dengan cara berikut:

1.  Menggunakan `for loop`
    

```python
for info in (jack, jenny):
    info.get_age()
    info.get_gender()
    info.get_address()
```

2. atau; Menggunakan class atau function lain
    

```python
class Extract:
    def get_info(self, object_class):
        object_class.get_age()
        object_class.get_gender()
        object_class.get_address()

extract = Extract()
extract.get_info(jack)
extract.get_info(jenny)
```

Kedua dua cara di atas akan menghasilkan output yang sama.

```python
Output:

Age: 19
Gender: male
Address: USA
Age: 21
Gender: female
Address: Colombia
```

## Gabungan konsep

Ketiga-tiga pendekatan diatas boleh digunakan secara bersendirian. Namun ini tidak bermakna kita tidak boleh menggabungkannya ataupun menggunakan satu pendekatan untuk mencipta pendekatan yang lain.

Contohnya:

> 1.  Perwarisan dan Polimorfism boleh digunakan untuk mencipta class yang mampu untuk *overriding atribut dari Class sebelumnya.*
>     
> 2.  Dalam pengkapsulan boleh ada sebuah perwarisan (antara subclass)
>     

# Penutup

Bentuk-bentuk ini bergantung kepada kesesuaian keadaan dan bagaimana seorang pengaturcara untuk menyelesaikan masalah yang dihadapinya semasa membangunakan sesebuah kod.

Idea untuk menentukan pendekatan yang mana lebih baik tidak hadir dalam masa yang singkat. Pengalaman yang ditambah secara konsisten dalam pengaturcaraan dan kaedah cubajaya dapat membantu pengaturcara untuk menentukan konsep yang terbaik.

Sampai disini sahaja artikel kali ini. Jangan lupa untuk cipta Class anda selepas ini menggunakan konsep-konsep diatas. Jika terdapat kekeliruan ataupun persoalan atau penambahbaikan, penulis mengalu-alukan komen pembaca pada ruangan dibawah.

Sampai jumpa, salam!
