Masukkan Password
61 6.10 What is Polymorphism in OOP | Flexibility & Reusability of Code in Dart OOP | Dart Course
Materi kali ini membahas salah satu konsep paling penting dalam OOP, yaitu Polymorphism (polimorfisme).
Kalau sebelumnya kita sudah belajar:
Class
↓
Object
↓
Constructor
↓
Encapsulation
↓
Inheritance
↓
Super
↓
Polymorphism
Maka polymorphism bisa dianggap sebagai lanjutan dari inheritance + method overriding.
1. Apa Itu Polymorphism?
Kata polymorphism berasal dari:
- poly = banyak
- morph = bentuk
Jadi secara sederhana:
Polymorphism = satu bentuk/interface, tetapi bisa memiliki banyak perilaku.
Dalam OOP, polymorphism memungkinkan kita memperlakukan object dari class yang berbeda sebagai tipe parent yang sama, tetapi ketika sebuah method dipanggil, program dapat menjalankan implementasi sesuai object sebenarnya.
Ini terdengar agak rumit, jadi kita gunakan contoh.
2. Contoh Paling Sederhana
Kita punya parent class:
class Person {
void speak() {
print("Person is speaking");
}
}
Kemudian child:
class Student extends Person {
@override
void speak() {
print("Student is speaking");
}
}
Perhatikan:
Person
└── speak()
Student extends Person
└── speak()
Student mempunyai method speak() dengan nama yang sama seperti parent.
Tetapi implementasinya berbeda.
Inilah yang disebut:
Method overriding
3. Apa Itu @override?
Di Dart kita biasanya menulis:
@override
void speak() {
print("Student is speaking");
}
@override memberi tahu Dart:
“Method ini dimaksudkan untuk menggantikan/menimpa implementasi method yang diwarisi dari parent.”
Jadi:
class Person {
void speak() {
print("Person is speaking");
}
}
class Student extends Person {
@override
void speak() {
print("Student is speaking");
}
}
Student.speak() meng-override Person.speak().
4. Sekarang Bagian yang Menarik
Biasanya kita membuat object seperti ini:
Student student = Student();
Artinya:
Tipe variabel → Student
Object → Student
Kemudian:
student.speak();
hasilnya:
Student is speaking
Ini tentu mudah dipahami.
Tapi polymorphism memungkinkan kita melakukan sesuatu yang lebih menarik.
5. Parent Type Menyimpan Child Object
Kita bisa menulis:
Person person = Student();
Awalnya ini mungkin terlihat aneh.
Bukankah person harus berisi object Person?
Ternyata boleh, karena Student extends Person.
Hubungannya:
Student IS-A Person
Karena Student adalah Person, object Student dapat diperlakukan sebagai Person.
Secara konsep:
Person
↑
│
Student
Maka:
Person person = Student();
valid.
6. Tapi Object Sebenarnya Tetap Student
Ini bagian sangat penting.
Perhatikan:
Person person = Student();
Ada dua hal berbeda:
Tipe variabel
Person
Object sebenarnya
Student
Jadi:
Variable type = Person
Object = Student
Atau:
Person person = Student();
↑ ↑
tipe object nyata
Ini adalah inti dari contoh polymorphism di video.
7. Ketika speak() Dipanggil
Sekarang:
Person person = Student();
person.speak();
Pertanyaannya:
Method
speak()milik siapa yang dijalankan?
Apakah:
Person.speak()
atau:
Student.speak()
Jawabannya:
Student.speak()
Output:
Student is speaking
Kenapa?
Karena object sebenarnya adalah:
Student()
Meskipun variabelnya bertipe:
Person
method yang dioverride akan menggunakan implementasi dari object sebenarnya.
8. Inilah Polymorphism
Kita bisa sederhanakan:
Person person = Student();
person.speak();
Artinya:
“Saya memiliki referensi bertipe
Person, tetapi object yang sebenarnya adalahStudent.”
Ketika:
person.speak();
Dart melihat object sebenarnya:
Person
↑
│
Student ← object sebenarnya
Kemudian menjalankan:
Student.speak()
9. Analogi Dunia Nyata
Bayangkan kita punya:
Animal
↑
┌───────┼───────┐
│ │ │
Cat Dog Bird
Semua adalah Animal.
Kita buat method:
void makeSound()
Tetapi suara masing-masing berbeda.
Cat → Meow
Dog → Woof
Bird → Tweet
Kita bisa memiliki:
Animal animal = Cat();
Kemudian:
animal.makeSound();
hasil:
Meow
Kemudian:
animal = Dog();
animal.makeSound();
hasil:
Woof
Kemudian:
animal = Bird();
animal.makeSound();
hasil:
Tweet
Interface yang digunakan tetap:
animal.makeSound()
Tetapi perilakunya berubah berdasarkan object.
Itulah polymorphism.
10. Contoh Lengkap Dart
class Animal {
void makeSound() {
print("Animal makes a sound");
}
}
class Cat extends Animal {
@override
void makeSound() {
print("Meow");
}
}
class Dog extends Animal {
@override
void makeSound() {
print("Woof");
}
}
Sekarang:
void main() {
Animal animal;
animal = Cat();
animal.makeSound();
animal = Dog();
animal.makeSound();
}
Output:
Meow
Woof
Perhatikan:
Animal animal;
Variabelnya hanya bertipe Animal.
Tetapi object bisa:
Cat()
atau:
Dog()
11. Kenapa Ini Berguna?
Nah, di sinilah konsep flexibility dan reusability yang disebut dalam video menjadi penting.
Bayangkan kita mempunyai function:
void makeAnimalSpeak(Animal animal) {
animal.makeSound();
}
Kita bisa memberikan berbagai object:
makeAnimalSpeak(Cat());
makeAnimalSpeak(Dog());
Output:
Meow
Woof
Function-nya tidak perlu dibuat dua kali.
Kita tidak perlu:
void makeCatSpeak(Cat cat) {}
void makeDogSpeak(Dog dog) {}
Cukup:
void makeAnimalSpeak(Animal animal) {
animal.makeSound();
}
Ini membuat kode lebih fleksibel.
12. Ini Contoh Reusability
Bayangkan nanti kita punya 100 jenis Animal.
Animal
├── Cat
├── Dog
├── Bird
├── Cow
├── Horse
├── Lion
├── Tiger
└── ...
Semua melakukan:
makeSound()
Kita cukup memiliki satu function:
void makeAnimalSpeak(Animal animal) {
animal.makeSound();
}
Function tersebut dapat menerima:
Cat
Dog
Bird
Cow
Horse
...
selama semuanya merupakan subclass Animal.
Inilah salah satu kekuatan polymorphism.
13. Hubungan Polymorphism dengan Inheritance
Polymorphism pada contoh ini tidak berdiri sendiri.
Kita membutuhkan inheritance:
class Student extends Person
Karena inheritance menciptakan hubungan:
Student IS-A Person
Baru kemudian kita bisa melakukan:
Person person = Student();
Jadi secara sederhana:
Inheritance
↓
Student extends Person
↓
Student adalah Person
↓
Person person = Student()
↓
Polymorphism
14. Hubungan dengan Method Overriding
Polymorphism juga sangat erat dengan overriding.
Kita memiliki:
class Person {
void speak() {
print("Person speaking");
}
}
Child:
class Student extends Person {
@override
void speak() {
print("Student speaking");
}
}
Kemudian:
Person person = Student();
person.speak();
Output:
Student speaking
Jadi:
Inheritance
+
Method overriding
+
Parent reference → Child object
↓
Polymorphism
15. Kenapa Tidak Langsung Student student = Student()?
Bisa saja.
Student student = Student();
student.speak();
Tetapi ini tidak terlalu menunjukkan kekuatan polymorphism.
Dengan:
Person person = Student();
kita dapat membuat kode yang bekerja terhadap tipe umum (Person), tanpa harus mengetahui secara spesifik object-nya adalah Student.
Ini sangat berguna ketika program semakin besar.
16. Contoh yang Lebih Nyata
Misalnya aplikasi pembayaran.
Kita punya:
Payment
├── CreditCardPayment
├── BankTransferPayment
└── EWalletPayment
Parent:
class Payment {
void pay() {
print("Processing payment");
}
}
Credit card:
class CreditCardPayment extends Payment {
@override
void pay() {
print("Paying with credit card");
}
}
Bank transfer:
class BankTransferPayment extends Payment {
@override
void pay() {
print("Paying with bank transfer");
}
}
E-wallet:
class EWalletPayment extends Payment {
@override
void pay() {
print("Paying with e-wallet");
}
}
Sekarang kita dapat membuat:
void processPayment(Payment payment) {
payment.pay();
}
Dan:
processPayment(CreditCardPayment());
processPayment(BankTransferPayment());
processPayment(EWalletPayment());
Output:
Paying with credit card
Paying with bank transfer
Paying with e-wallet
Function:
processPayment()
tidak perlu tahu detail masing-masing payment.
Dia cukup tahu:
“Yang saya terima adalah
Payment, danPaymentpunyapay().”
Ini adalah polymorphism yang sangat berguna dalam aplikasi nyata.
17. Static Type vs Runtime Object
Ada konsep sedikit lebih dalam yang penting untuk dipahami.
Pada:
Person person = Student();
ada dua hal:
Static type
Person
Ini adalah tipe yang diketahui compiler untuk variabel person.
Runtime type
Object yang sebenarnya:
Student
Saat method virtual/overridden dipanggil:
person.speak();
implementasi yang sesuai dengan object sebenarnya (Student) yang dipilih.
Secara sederhana:
Person person = Student();
│ │
│ └── object sebenarnya
└── static type
person.speak()
↓
Student.speak()
Inilah yang sering disebut dynamic dispatch.
Untuk level pemula, kamu cukup ingat:
Tipe variabel boleh parent, tetapi object sebenarnya bisa child; method override yang sesuai object akan dijalankan.
18. Kalau Object-nya Memang Person?
Sekarang bandingkan:
Person person = Person();
person.speak();
Object sebenarnya:
Person
Maka yang dijalankan:
Person.speak()
Output:
Person is speaking
Sedangkan:
Person person = Student();
person.speak();
object sebenarnya:
Student
Maka:
Student.speak()
19. Bandingkan Dua Kondisi Ini
Kondisi 1
Person person = Person();
person.speak();
Hasil:
Person is speaking
Kondisi 2
Person person = Student();
person.speak();
Hasil:
Student is speaking
Padahal keduanya sama-sama:
person.speak();
Inilah bagian “poly” atau banyak bentuk perilaku.
20. Apakah Parent Bisa Memanggil Method Khusus Child?
Ada batas penting.
Misalnya:
class Person {
void speak() {
print("Person");
}
}
class Student extends Person {
@override
void speak() {
print("Student");
}
void study() {
print("Studying");
}
}
Kalau:
Person person = Student();
kita bisa:
person.speak(); // ✅
Tetapi:
person.study(); // ❌
Kenapa?
Karena study() tidak didefinisikan pada Person.
Variabel person bertipe Person, sehingga compiler hanya mengizinkan interface yang tersedia pada Person.
Ini penting:
Polymorphism tidak berarti parent reference otomatis bisa mengakses semua fitur child.
21. Lalu Bagaimana Kalau Ingin Mengakses Fitur Child?
Bisa menggunakan type checking/casting, tetapi untuk materi sekarang belum perlu terlalu dalam.
Contoh:
Person person = Student();
if (person is Student) {
person.study();
}
Karena Dart mengetahui di dalam blok tersebut bahwa person adalah Student.
Tetapi untuk penggunaan polymorphism yang baik, biasanya kita merancang parent interface agar operasi umum memang tersedia di parent.
22. Polymorphism dengan Banyak Child
Misalnya:
class Person {
void speak() {
print("Person speaking");
}
}
class Student extends Person {
@override
void speak() {
print("Student speaking");
}
}
class Doctor extends Person {
@override
void speak() {
print("Doctor speaking");
}
}
Kita bisa:
Person person;
person = Student();
person.speak();
person = Doctor();
person.speak();
Output:
Student speaking
Doctor speaking
Strukturnya:
Person
/ \
↓ ↓
Student Doctor
│ │
speak() speak()
│ │
↓ ↓
Student Doctor
speaking speaking
Interface sama:
person.speak();
Perilakunya berbeda.
23. Ini yang Dimaksud “Common Interface”
Caption menyebut:
different objects can be treated as instances of a common superclass
Artinya kurang lebih:
Student dan Doctor dapat diperlakukan sebagai Person.
Person student = Student();
Person doctor = Doctor();
Keduanya memiliki tipe parent:
Person
sehingga kita dapat menggunakan operasi yang disediakan oleh Person.
24. Analogi Remote Control
Bayangkan ada remote dengan tombol:
[ POWER ]
[ VOLUME ]
[ CHANNEL ]
Remote memiliki interface yang sama.
Tetapi perangkatnya bisa:
TV
AC
Speaker
Cara menggunakan tombolnya mungkin sama:
POWER
tetapi perilaku internalnya berbeda.
Begitu juga polymorphism:
device.turnOn();
device bisa saja:
TV
Speaker
AC
Interface:
turnOn()
sama.
Implementasinya berbeda.
25. Kesalahan yang Sering Dilakukan Pemula
❌ Mengira ini salah
Person person = Student();
Sebenarnya benar, selama Student extends Person.
❌ Mengira method parent yang selalu dipanggil
Person person = Student();
person.speak();
Kalau Student meng-override speak(), maka implementasi Student.speak() yang dipanggil.
❌ Mengira @override membuat method parent hilang
Tidak.
Parent tetap mempunyai:
Person.speak()
Child hanya menyediakan implementasi sendiri untuk method tersebut.
Kalau ingin secara eksplisit menjalankan versi parent dari child:
super.speak();
Ini menghubungkan materi polymorphism dengan materi super sebelumnya.
26. Hubungan super dan @override
Misalnya:
class Person {
void speak() {
print("Person speaking");
}
}
class Student extends Person {
@override
void speak() {
super.speak();
print("Student speaking");
}
}
Ketika:
Person person = Student();
person.speak();
alur sederhananya:
person.speak()
↓
Student.speak()
↓
super.speak()
↓
Person.speak()
↓
kembali ke Student
↓
print Student speaking
Output:
Person speaking
Student speaking
27. Polymorphism Bukan Sekadar “Parent = Child”
Ini poin penting.
Kode:
Person person = Student();
sendiri memang merupakan bagian penting.
Tetapi polymorphism benar-benar terlihat ketika kita menggunakan interface parent untuk berinteraksi dengan object child:
Person person = Student();
person.speak();
dan method yang dijalankan mengikuti object sebenarnya:
Person reference
↓
Student object
↓
Student.speak()
Jadi jangan hanya menghafal:
Parent object = Child();
Tetapi pahami:
Saya menggunakan tipe parent untuk berinteraksi dengan berbagai object child melalui interface yang sama.
28. Contoh Praktik yang Bagus
Kita buat:
class Shape {
double area() {
return 0;
}
}
Kemudian:
class Rectangle extends Shape {
double width;
double height;
Rectangle(this.width, this.height);
@override
double area() {
return width * height;
}
}
Circle:
import 'dart:math';
class Circle extends Shape {
double radius;
Circle(this.radius);
@override
double area() {
return pi * radius * radius;
}
}
Sekarang kita bisa membuat:
void printArea(Shape shape) {
print(shape.area());
}
Dan:
void main() {
printArea(Rectangle(10, 5));
printArea(Circle(7));
}
Function yang sama:
printArea()
bisa menerima:
Rectangle
Circle
karena keduanya adalah:
Shape
Dan area() akan melakukan hal yang berbeda.
Ini adalah contoh polymorphism yang sangat kuat dan realistis.
29. Ringkasan Semua Konsep yang Sudah Kamu Pelajari
Sekarang materi OOP-mu mulai saling terhubung.
CLASS
↓
OBJECT
↓
CONSTRUCTOR
↓
NAMED CONSTRUCTOR
↓
CONST CONSTRUCTOR
↓
ENCAPSULATION
↓
GETTER / SETTER
↓
INHERITANCE
↓
SUPER
↓
METHOD OVERRIDING
↓
POLYMORPHISM
Dan hubungan polymorphism:
Parent
↑
│ extends
│
Child
│
└── override method
↓
Parent reference
↓
Child object
↓
Child implementation dijalankan
🧠 Cara Memahami Polymorphism dalam 1 Kalimat
Kalau harus mengingat satu kalimat saja, ingat ini:
Polymorphism memungkinkan kita menggunakan tipe parent untuk menangani berbagai object child, sementara method yang dijalankan mengikuti object sebenarnya.
Contoh paling penting:
class Person {
void speak() {
print("Person");
}
}
class Student extends Person {
@override
void speak() {
print("Student");
}
}
void main() {
Person person = Student();
person.speak();
}
Hasil:
Student
Kenapa?
Person person = Student();
│ │
│ └── object sebenarnya = Student
└── tipe reference = Person
person.speak()
↓
Student.speak()
⭐ Tiga kata kunci yang perlu kamu ingat
INHERITANCE
↓
OVERRIDING
↓
POLYMORPHISM
Inheritance membuat Student menjadi turunan Person.
Overriding membuat Student memiliki versi speak() sendiri.
Polymorphism memungkinkan kita menulis:
Person person = Student();
person.speak();
tetapi yang dijalankan adalah:
Student.speak()
Jadi, kalau pada materi sebelumnya super mengajarkan kamu bagaimana child dapat mengakses parent, maka polymorphism mengajarkan bagaimana kita dapat menggunakan parent interface untuk menangani berbagai child object dengan perilaku yang berbeda.
buatkan script konten youtube durasi 5 menit dengan tema diatas, gunakan gaya penyampaian yang naratif, detail, dan mudah dipahami oleh pemula, gaya video explainer seperti chanel coding2go