Masukkan Password
56 Dart extends and implements - What's the Difference? | Dart Tutorial #56
Video ini sebenarnya adalah ringkasan besar tentang perbedaan extends dan implements setelah sebelumnya membahas interface secara terpisah.
Saya akan jelaskan dari dasar, lalu kita bedah satu per satu poin dari transcript. Ada beberapa kalimat di video yang perlu diluruskan supaya sesuai dengan Dart modern, terutama istilah “method diwariskan sebagai abstract declaration” dan soal field.
1. Gambaran paling sederhana
Sebelum masuk ke detail, hafalkan dulu ini:
extends
↓
"Mewarisi"
implements
↓
"Memenuhi contract"
Misalnya:
class Animal {
void sound() {
print("Animal sound");
}
}
Kalau:
class Cat extends Animal {
}
artinya:
Catadalah turunan dariAnimaldan mendapatkan implementasisound()dariAnimal.
Sedangkan:
class Cat implements Animal {
}
artinya:
Cattidak mewarisi implementasisound()dariAnimal.Cathanya mengatakan bahwa dirinya memenuhi contractAnimal.
Karena itu Cat harus menyediakan sound() sendiri.
2. extends = inheritance
Contoh:
class Animal {
void sound() {
print("Animal sound");
}
void sleep() {
print("Animal sleeping");
}
}
class Cat extends Animal {
}
Sekarang Cat otomatis mendapatkan:
sound()
sleep()
Jadi:
void main() {
Cat cat = Cat();
cat.sound();
cat.sleep();
}
Output:
Animal sound
Animal sleeping
Kita tidak perlu menulis ulang method tersebut di Cat.
3. implements = contract
Sekarang ubah:
class Cat extends Animal
menjadi:
class Cat implements Animal
Maka:
class Cat implements Animal {
}
akan error karena Cat belum memenuhi contract dari Animal.
Kita harus menulis:
class Cat implements Animal {
@override
void sound() {
print("Cat: Meow");
}
@override
void sleep() {
print("Cat sleeping");
}
}
Perhatikan sesuatu yang sangat penting.
Animal sebenarnya mempunyai implementasi:
void sleep() {
print("Animal sleeping");
}
Tetapi karena kita menggunakan:
implements Animal
implementasi tersebut tidak diwariskan ke Cat.
Jadi Cat harus membuat implementasinya sendiri.
4. Perbedaan utama: implementasi vs contract
Ini inti seluruh video.
Bayangkan Animal seperti sebuah kontrak.
Kontrak mengatakan:
Animal harus memiliki:
- sound()
- sleep()
Dengan:
class Cat implements Animal
Cat berkata:
“Saya setuju memenuhi kontrak tersebut.”
Tetapi Cat bebas menentukan implementasinya sendiri.
Misalnya:
class Cat implements Animal {
@override
void sound() {
print("Meow");
}
@override
void sleep() {
print("Cat is sleeping");
}
}
Sedangkan dengan:
class Cat extends Animal
Cat berkata:
“Saya adalah turunan Animal dan akan mewarisi implementasi yang tersedia.”
5. Apakah extends selalu berarti tidak perlu override?
Tidak.
Video mengatakan override pada extends bersifat optional. Itu benar untuk method konkret yang sudah memiliki implementasi, tetapi ada pengecualian penting.
Misalnya:
class Animal {
void sound() {
print("Animal sound");
}
}
class Cat extends Animal {
}
Tidak perlu override.
Tetapi kalau superclass memiliki abstract method:
abstract class Animal {
void sound();
}
kemudian:
class Cat extends Animal {
}
Cat masih error karena Cat adalah concrete class dan belum menyediakan sound().
Harus:
class Cat extends Animal {
@override
void sound() {
print("Meow");
}
}
Jadi lebih tepat:
Pada
extends, method konkret boleh diwarisi tanpa override. Tetapi abstract member harus diselesaikan oleh concrete subclass.
6. Kenapa implements bisa banyak?
Dart hanya mengizinkan satu superclass langsung.
Tidak boleh:
class C extends A, B {
}
Tetapi boleh:
class C implements A, B {
}
Misalnya:
class Flyable {
void fly() {
print("Flying");
}
}
class Swimmable {
void swim() {
print("Swimming");
}
}
Kemudian:
class Duck implements Flyable, Swimmable {
@override
void fly() {
print("Duck flying");
}
@override
void swim() {
print("Duck swimming");
}
}
Duck memenuhi dua contract:
Flyable
↓
fly()
Swimmable
↓
swim()
↓
Duck
├── fly()
└── swim()
7. Kenapa multiple extends tidak diperbolehkan?
Sekarang kita lihat alasan desainnya.
Misalnya secara hipotetis Dart memperbolehkan:
class A {
void test() {
print("A");
}
}
class B {
void test() {
print("B");
}
}
class C extends A, B {
}
C mendapatkan dua:
A.test()
B.test()
Kemudian:
C obj = C();
obj.test();
Pertanyaannya:
Yang harus dipanggil
A.test()atauB.test()?
Ini menyebabkan konflik.
Dalam OOP masalah seperti ini sering dikaitkan dengan diamond problem atau ambiguity pada multiple inheritance.
Dart memilih desain:
extends
→ hanya satu superclass
Tetapi:
implements
→ bisa banyak interface
Karena interface hanya memberikan contract, bukan dua implementasi method yang harus digabungkan.
8. implements tidak berarti “method abstract benar-benar diwariskan”
Ini salah satu bagian transcript yang perlu kita luruskan.
Video mengatakan kurang lebih:
“implements hanya mewariskan abstract method declaration.”
Untuk pemahaman pemula, maksudnya memang seperti itu.
Tetapi secara konsep yang lebih tepat:
implementsmembuat class harus memenuhi interface dari class tersebut. Implementasi method dari class sumber tidak diwariskan.
Misalnya:
class A {
void test() {
print("A");
}
}
Kemudian:
class B implements A {
@override
void test() {
print("B");
}
}
Bukan berarti Dart benar-benar melakukan proses seperti:
class B {
abstract void test(); // bukan kode Dart literal seperti ini
}
Lebih tepat membayangkannya:
A interface
↓
"Harus punya test()"
B
↓
harus menyediakan test()
Jadi interface adalah contract, bukan proses copy-paste method menjadi abstract method secara literal.
9. Concrete class vs abstract class
Ini juga penting.
Misalnya:
class A {
void test() {}
}
Kemudian:
class B implements A {
}
Error.
Karena B concrete dan belum memenuhi contract.
Tetapi:
abstract class B implements A {
}
boleh.
Kenapa?
Karena abstract class boleh belum menyelesaikan semua requirement.
Contohnya:
class A {
void test() {
print("A");
}
}
abstract class B implements A {
}
class C extends B {
@override
void test() {
print("C");
}
}
Alurnya:
A
↓
interface contract
B
↓
abstract
↓
boleh belum implementasi
C
↓
concrete
↓
harus menyelesaikan
10. Constructor: extends vs implements
Ini perbedaan besar lainnya.
Dengan extends
class A {
A() {
print("Constructor A");
}
}
class B extends A {
B() {
print("Constructor B");
}
}
Ketika:
B();
output:
Constructor A
Constructor B
Karena A adalah superclass.
Dengan implements
class A {
A() {
print("Constructor A");
}
void test() {}
}
class B implements A {
B() {
print("Constructor B");
}
@override
void test() {}
}
Ketika:
B();
output:
Constructor B
Constructor A tidak dipanggil.
11. Kenapa constructor A tidak dipanggil?
Karena:
class B implements A
tidak berarti:
B adalah subclass A.
Artinya:
B memenuhi interface A.
A tidak menjadi superclass B.
Jadi tidak ada initialization chain:
A constructor
↓
B constructor
Yang ada hanya:
B constructor
12. super pada extends
Dengan inheritance:
class A {
void test() {
print("A");
}
}
class B extends A {
@override
void test() {
print("B");
super.test();
}
}
Output:
B
A
super.test() berarti:
Panggil implementasi
test()dari superclass A.
13. super tidak berlaku untuk interface
Kalau:
class A {
void test() {
print("A");
}
}
class B implements A {
@override
void test() {
print("B");
super.test(); // ❌
}
}
Ini error.
Karena A bukan superclass B.
Ingat:
extends A
A = superclass
↓
super.test() bisa
Sedangkan:
implements A
A = interface
↓
super.test() tidak bisa
14. Bagaimana dengan field?
Ini bagian transcript yang agak membingungkan.
Misalnya:
class A {
int data = 10;
}
Dengan:
class B extends A {
}
B mendapatkan data.
void main() {
B obj = B();
print(obj.data);
}
Output:
10
Tidak perlu membuat data lagi.
Tetapi implements
class B implements A {
}
B harus memenuhi contract data.
Misalnya:
class B implements A {
@override
int data = 20;
}
Sekarang B punya data sendiri.
Nilai 10 dari A tidak diwariskan.
15. Field sebenarnya berhubungan dengan getter/setter
Ini konsep yang bagus untuk dipahami.
Ketika interface memiliki:
int data = 10;
implementasinya bukan sekadar:
“B harus mempunyai storage variable bernama data.”
Secara interface, property tersebut berkaitan dengan accessor.
Untuk field mutable:
int data;
ada kemampuan:
get data
set data
Karena itu kita bisa memenuhi contract dengan getter/setter:
class A {
int data = 10;
}
Implementasinya:
class B implements A {
int _myData = 20;
@override
int get data {
return _myData;
}
@override
set data(int value) {
_myData = value;
}
}
Jadi nama storage-nya boleh berbeda:
Interface:
data
Implementasi:
_myData
↑
storage internal
get data
set data
↑
memenuhi contract
16. Bagaimana dengan getter dan setter?
Misalnya interface:
class A {
int _x = 10;
int get x => _x;
set x(int value) {
_x = value;
}
}
Kalau:
class B implements A {
}
B harus memenuhi getter dan setter tersebut.
Misalnya:
class B implements A {
int _value = 20;
@override
int get x => _value;
@override
set x(int value) {
_value = value;
}
}
Jadi:
interface A
├── get x
└── set x
B implements A
├── get x
└── set x
17. Tetapi extends berbeda
Dengan:
class B extends A {
}
B mendapatkan getter/setter dari A.
Tidak wajib menulis ulang.
Kalau mau mengganti perilaku, baru override.
18. “Guideline” vs “Specification”
Video menggunakan istilah:
guideline dan specification.
Cara gampang memahaminya:
extends
Memberikan implementasi yang bisa langsung digunakan.
class Animal {
void sleep() {
print("Sleeping");
}
}
class Cat extends Animal {
}
Cat langsung bisa menggunakan:
cat.sleep();
implements
Memberikan contract yang harus dipenuhi.
class Animal {
void sleep() {
print("Sleeping");
}
}
class Cat implements Animal {
@override
void sleep() {
print("Cat sleeping");
}
}
Cat tidak mendapatkan implementasi sleep() dari Animal.
Cat harus membuatnya sendiri.
19. extends concrete class
class A {
void test() {
print("A");
}
}
class B extends A {
}
B mendapatkan implementasi:
B
└── test()
↓
implementasi A
20. extends abstract class
Misalnya:
abstract class Animal {
void sound();
void sleep() {
print("Sleeping");
}
}
Kemudian:
class Cat extends Animal {
@override
void sound() {
print("Meow");
}
}
Cat mendapatkan:
sound()
↓
harus implement sendiri
sleep()
↓
warisi dari Animal
Ini contoh yang sangat bagus untuk memahami abstract class.
21. implements abstract class
Sekarang:
abstract class Animal {
void sound();
void sleep() {
print("Sleeping");
}
}
Kemudian:
class Cat implements Animal {
}
Cat harus menyediakan keduanya:
class Cat implements Animal {
@override
void sound() {
print("Meow");
}
@override
void sleep() {
print("Cat sleeping");
}
}
Kenapa sleep() juga harus ditulis?
Karena walaupun sleep() sudah memiliki body di Animal, kita menggunakan:
implements
bukan:
extends
22. Ini perbedaan yang sering keluar dalam interview
Misalnya:
abstract class Animal {
void sound();
void sleep() {
print("Sleeping");
}
}
A:
class Cat extends Animal
Maka:
sound()
→ wajib diimplementasikan
sleep()
→ sudah tersedia
→ tidak wajib override
B:
class Cat implements Animal
Maka:
sound()
→ wajib implementasi
sleep()
→ juga wajib implementasi
Ini sangat penting.
23. extends + implements sekaligus
Dart memungkinkan:
class C extends B implements A {
}
Misalnya:
class A {
void test() {
print("A");
}
}
class B {
void test() {
print("B");
}
}
class C extends B implements A {
}
Apakah C harus membuat test()?
Tidak.
Karena C mewarisi:
B.test()
dan test() tersebut memenuhi contract A.
Jadi:
C().test();
menghasilkan:
B
24. Kalau C membuat override?
class C extends B implements A {
@override
void test() {
print("C");
}
}
Sekarang:
C().test();
output:
C
Urutannya secara sederhana:
A
↓
contract test()
B
↓
punya implementasi test()
C
├── extends B
└── implements A
Karena B sudah menyediakan test(), contract A sudah terpenuhi.
25. implements + multiple interface
Misalnya:
class Flyable {
void fly() {}
}
class Swimmable {
void swim() {}
}
class Duck implements Flyable, Swimmable {
@override
void fly() {
print("Flying");
}
@override
void swim() {
print("Swimming");
}
}
Duck sekarang dapat dianggap sebagai:
Flyable
+
Swimmable
Contohnya:
void makeItFly(Flyable animal) {
animal.fly();
}
void makeItSwim(Swimmable animal) {
animal.swim();
}
Kemudian:
Duck duck = Duck();
makeItFly(duck);
makeItSwim(duck);
Ini salah satu manfaat interface untuk polymorphism.
26. Kenapa interface bagus untuk polymorphism?
Misalnya kita punya:
abstract class Payment {
void pay(double amount);
}
Kemudian:
class CreditCard implements Payment {
@override
void pay(double amount) {
print("Pay $amount using credit card");
}
}
dan:
class EWallet implements Payment {
@override
void pay(double amount) {
print("Pay $amount using e-wallet");
}
}
Kita bisa membuat:
void checkout(Payment payment) {
payment.pay(100);
}
Sekarang:
checkout(CreditCard());
checkout(EWallet());
Function checkout() tidak perlu tahu:
“Ini CreditCard atau EWallet?”
Dia hanya tahu:
“Object ini adalah
Payment.”
Ini adalah kekuatan interface.
27. Bagaimana dengan constructor superclass tanpa default constructor?
Misalnya:
class A {
A(int x) {
print("A: $x");
}
}
Kemudian:
class B extends A {
B() : super(10);
}
Harus memanggil constructor A yang sesuai.
Kalau tidak:
class B extends A {
B(); // ❌
}
akan bermasalah karena A tidak mempunyai unnamed zero-argument constructor yang bisa digunakan secara otomatis.
Jadi:
B()
↓
super(10)
↓
A(10)
28. Tetapi implements tidak membutuhkan super
Misalnya:
class A {
A(int x) {
print("A: $x");
}
void test() {}
}
Kemudian:
class B implements A {
B();
@override
void test() {}
}
Tidak perlu:
super(10)
Karena A bukan superclass.
B tidak sedang membangun bagian object A.
29. Bahkan super() tidak bisa digunakan untuk memanggil constructor interface
Misalnya:
class A {
A(int x);
void test() {}
}
class B implements A {
B() : super(10); // ❌
@override
void test() {}
}
Tidak boleh.
Karena:
A bukan superclass B
super hanya berhubungan dengan superclass langsung.
30. Kesalahan konsep yang perlu diperbaiki dari video
Ada beberapa istilah transcript yang sebaiknya jangan kamu hafalkan mentah-mentah.
❌ “implements mewariskan abstract method”
Lebih tepat:
implementsmembuat class harus memenuhi interface/contract dari type tersebut. Implementasi method tidak diwariskan.
❌ “interface adalah superclass”
Tidak.
Kalau:
class B implements A
A bukan superclass B.
A adalah interface yang digunakan B.
❌ “extends selalu tidak perlu override”
Tidak selalu.
Kalau superclass mempunyai abstract member, concrete subclass harus mengimplementasikannya.
❌ “field harus di-override dengan field yang sama”
Tidak harus berupa field dengan storage yang sama.
Contract property bisa dipenuhi melalui getter/setter yang kompatibel.
31. Cheat sheet super cepat
| Pertanyaan | extends | implements |
|---|---|---|
| Hubungan | inheritance | contract/interface |
| Jumlah | 1 superclass | bisa banyak |
| Implementasi method diwarisi? | ✅ | ❌ |
| Concrete method perlu override? | ❌ tidak wajib | ✅ wajib dipenuhi |
| Abstract method | harus diselesaikan concrete subclass | harus dipenuhi concrete class |
| Constructor superclass terlibat? | ✅ | ❌ |
| Constructor interface dipanggil? | — | ❌ |
super.method() | ✅ | ❌ |
| Getter/setter diwarisi? | ✅ | ❌ |
| Field instance diwarisi? | ✅ | ❌ |
| Static member jadi contract instance? | ❌ | ❌ |
32. Diagram yang paling penting
Kalau kamu melihat:
class B extends A
bayangkan:
A
┌───────────┐
│ test() │
│ sleep() │
└───────────┘
▲
│ extends
│
┌───────────┐
│ B │
│ │
│ mewarisi │
│ implementasi
└───────────┘
Sedangkan:
class B implements A
bayangkan:
A
┌────────────┐
│ CONTRACT │
│ test() │
│ sleep() │
└────────────┘
│
│ implements
▼
┌────────────┐
│ B │
│ │
│ test() │ ← implementasi sendiri
│ sleep() │ ← implementasi sendiri
└────────────┘
33. Hubungkan dengan materi sebelumnya
Sekarang konsep-konsep yang sudah kita pelajari mulai menyatu:
class
│
├── extends
│ ↓
│ inheritance
│
├── implements
│ ↓
│ interface / contract
│
├── @override
│ ↓
│ mengganti/menyediakan implementasi
│
├── super
│ ↓
│ akses superclass
│
└── abstract
↓
class yang boleh memiliki
member tanpa implementasi
Dan:
extends
→ "Saya adalah turunan dari kamu."
implements
→ "Saya mengikuti contract kamu."
super
→ "Saya mau mengakses bagian superclass."
@override
→ "Saya menyediakan/mengganti implementasi member."
abstract
→ "Class ini boleh belum lengkap."
34. Kaitannya dengan Flutter
Ini sangat penting karena kamu sedang belajar Flutter.
Contoh yang sangat umum:
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return const Text("Hello");
}
}
Di sini:
extends StatelessWidget
berarti MyPage adalah subclass dari StatelessWidget.
Kemudian:
@override
Widget build(...)
berarti MyPage menyediakan implementation build() yang diwajibkan/ditentukan oleh superclass.
Jadi kamu sekarang bisa melihat:
MyPage
│
│ extends
↓
StatelessWidget
│
└── build()
↑
@override
Dan Flutter juga banyak menggunakan composition, bukan inheritance saja. Jadi jangan sampai setelah belajar extends kamu menganggap semua struktur Flutter harus dibuat dengan inheritance.
Kesimpulan paling penting
Kalau besok kamu lupa semua isi video ini, cukup ingat kalimat berikut:
extends= mendapatkan/mewarisi implementasi dari superclass.
implements= tidak mendapatkan implementasi; kita hanya mengambil contract/interface dan harus memenuhi contract tersebut.
Contoh paling sederhana:
class A {
void test() {
print("A");
}
}
extends
class B extends A {
}
Bisa langsung:
B().test();
Output:
A
Karena implementasi diwarisi.
implements
class B implements A {
@override
void test() {
print("B");
}
}
Output:
B
Karena B membuat implementasinya sendiri.
Dan inilah inti seluruh video:
extends
↓
┌─────────────────┐
│ INHERITANCE │
│ │
│ "Berikan kode │
│ dan behavior-mu"│
└─────────────────┘
implements
↓
┌─────────────────┐
│ INTERFACE │
│ │
│ "Saya akan │
│ memenuhi │
│ contract-mu" │
└─────────────────┘
Kalimat kunci untuk dihafal:
🟦
extends→ IS-A + mewarisi implementasi 🟩implements→ IS-A contract + membuat implementasi sendiri 🟨super→ hanya untuk superclass, bukan interface 🟥implementsbisa lebih dari satu,extendshanya satu superclass langsung.