Masukkan Password
49 10 essential Inheritance questions | Dart inheritance doubts | Dart Tutorial #49
Video ini sebenarnya adalah pendalaman inheritance di Dart. Kalau video sebelumnya membahas βapa itu inheritanceβ, video ini mencoba menjawab 10 pertanyaan yang sering muncul setelah memahami extends.
Saya akan jelaskan satu per satu dengan bahasa sederhana, sekaligus meluruskan beberapa bagian transcript yang kurang tepat atau sudah tidak sesuai dengan Dart modern.
Gambaran besar
Materi video ini membahas:
- Kenapa Dart tidak mendukung multiple inheritance?
- Kenapa panah inheritance biasanya digambar ke atas?
- Kenapa tidak copy-paste kode saja?
- Kenapa constructor tidak diwariskan?
- Bagaimana private member dalam inheritance?
- Apakah semua class Dart selalu punya inheritance?
- Apakah inheritance penting dalam Flutter?
- Apakah belajar
extendssaja sudah cukup? - Apakah class bisa dibuat
finalagar tidak bisa diwariskan? - Apa bedanya inheritance dengan association, aggregation, dan composition?
Kita mulai dari yang paling penting.
1. Kenapa Dart tidak mendukung Multiple Inheritance?
Pertama, kita harus memahami dulu apa itu multiple inheritance.
Multiple inheritance adalah kondisi ketika satu subclass memiliki lebih dari satu superclass langsung.
Misalnya secara konsep:
A B
\ /
\ /
C
Artinya:
C mewarisi A
C juga mewarisi B
Dalam bahasa seperti C++ terdapat konsep multiple inheritance.
Tetapi Dart tidak mengizinkan:
class A {
}
class B {
}
// β Tidak valid di Dart
class C extends A, B {
}
Satu class Dart hanya bisa mempunyai satu superclass langsung melalui extends.
Kenapa?
Salah satu masalah klasik adalah ambiguity atau kebingungan ketika dua parent mempunyai member dengan nama yang sama.
Misalnya:
class A {
void demo() {
print("Demo from A");
}
}
class B {
void demo() {
print("Demo from B");
}
}
Bayangkan seandainya Dart mengizinkan:
A B
\ /
\ /
C
Maka C akan memiliki dua demo():
C
βββ demo() dari A
βββ demo() dari B
Kemudian:
C obj = C();
obj.demo();
Pertanyaannya:
demo()yang mana?
Apakah:
A.demo()
atau:
B.demo()
Inilah yang disebut ambiguity.
Analogi sederhana
Bayangkan kamu punya dua orang guru:
Guru A β mengajarkan "Cara belajar"
Guru B β mengajarkan "Cara belajar"
Kemudian kamu menjadi murid dari keduanya.
Lalu keduanya memanggil:
“Ikuti cara belajar saya!”
Kamu akan bertanya:
“Saya harus mengikuti yang mana?”
Itulah kira-kira masalah yang bisa muncul pada multiple inheritance.
2. Apakah ambiguity satu-satunya alasan?
Tidak.
Multiple inheritance dapat menimbulkan berbagai persoalan desain, terutama ketika hierarchy menjadi kompleks.
Contoh klasiknya adalah diamond problem:
A
/ \
B C
\ /
D
B dan C sama-sama berasal dari A.
Kemudian D mewarisi B dan C.
Pertanyaannya:
Kalau
Amemiliki suatu member, bagaimana tepatnya member itu muncul melaluiBdanC?
Situasinya bisa menjadi rumit.
Karena itu Dart memilih desain inheritance yang lebih sederhana:
Satu class
β
satu superclass langsung
Tetapi Dart tetap menyediakan mixin untuk menggunakan behavior dari beberapa sumber.
Contohnya:
mixin CanFly {
void fly() {
print("Flying");
}
}
mixin CanSwim {
void swim() {
print("Swimming");
}
}
class Duck with CanFly, CanSwim {
}
Sekarang:
Duck duck = Duck();
duck.fly();
duck.swim();
Jadi jangan menyimpulkan:
“Dart tidak bisa mendapatkan kemampuan dari banyak class.”
Yang lebih tepat:
Dart tidak mendukung multiple inheritance melalui
extends, tetapi memiliki mixin untuk reuse behavior dari beberapa sumber.
3. Kenapa panah inheritance mengarah ke atas?
Ini lebih berkaitan dengan konvensi diagram OOP/UML.
Misalnya:
Person
β
|
Employee
Employee adalah subclass.
Person adalah superclass.
Kenapa panah mengarah ke Person?
Karena arah panah menunjukkan:
Employee bergantung/merujuk kepada superclass Person sebagai parent type.
Jangan terlalu terpaku pada kalimat transcript:
“Person tidak memberikan sesuatu, Employee meminta sesuatu.”
Itu hanya analogi untuk menjelaskan arah panah, bukan aturan teknis Dart.
Yang penting kamu hafal:
Superclass
β
|
Subclass
Misalnya:
class Person {
}
class Employee extends Person {
}
Diagram:
Person
β
|
Employee
4. Kenapa tidak copy-paste saja?
Ini pertanyaan yang sangat bagus.
Misalnya kita mempunyai:
class Employee {
void work() {}
void login() {}
void calculateSalary() {}
}
Kemudian Manager membutuhkan semua method tersebut.
Cara pertama:
copy-paste
Kita copy:
work()
login()
calculateSalary()
ke Manager.
Kemudian Developer juga membutuhkan:
work()
login()
calculateSalary()
Kita copy lagi.
Awalnya tidak masalah.
Tetapi bayangkan aplikasi besar:
Employee
Manager
Developer
Designer
Accountant
HR
Director
Supervisor
...
Semua mempunyai kode yang sama.
5. Masalah pertama: Code Duplication
Misalnya:
class Manager {
void login() {
print("Login");
}
}
class Developer {
void login() {
print("Login");
}
}
class Designer {
void login() {
print("Login");
}
}
Method yang sama ditulis tiga kali.
Ini disebut:
code duplication
atau:
code redundancy
6. Masalah kedua: ukuran kode membesar
Semakin banyak class, semakin banyak kode yang harus ditulis.
Misalnya ada 20 class dan masing-masing harus mempunyai 10 method yang sama.
Secara kasar:
20 Γ 10 = 200 method
padahal sebenarnya kita mungkin hanya membutuhkan 10 implementasi yang digunakan bersama.
Dengan inheritance:
class Employee {
void login() {
print("Login");
}
}
class Manager extends Employee {
}
class Developer extends Employee {
}
class Designer extends Employee {
}
Sekarang ketiganya dapat menggunakan:
login()
tanpa menulis ulang.
7. Masalah terbesar: maintenance
Ini alasan yang sangat penting.
Misalnya kita mempunyai:
class Employee {
void login() {
print("Employee login");
}
}
Kemudian ada:
Manager
Developer
Designer
Accountant
HR
Kalau kita copy-paste, setiap class mempunyai salinan sendiri.
Kemudian requirement berubah:
"Login harus menampilkan waktu login."
Kamu harus mengubah:
Manager
Developer
Designer
Accountant
HR
...
satu per satu.
Bisa saja ada yang lupa diubah.
8. Dengan inheritance
Kita cukup mempunyai:
class Employee {
void login() {
print("Employee login with timestamp");
}
}
Kemudian:
class Manager extends Employee {
}
class Developer extends Employee {
}
class Designer extends Employee {
}
Mereka mendapatkan perubahan dari superclass.
Secara konsep:
Employee
|
βββββββββββΌββββββββββ
β β β
Manager Developer Designer
Jadi satu perubahan pada behavior yang memang dimiliki bersama dapat digunakan oleh subclass.
Catatan penting: inheritance bukan berarti setiap perubahan di parent selalu tepat untuk semua child. Kalau behavior sebenarnya tidak cocok untuk semua subclass, inheritance justru bisa menjadi desain yang buruk. Jadi jangan menggunakan inheritance hanya demi mengurangi duplikasi.
9. Kenapa constructor tidak diwariskan?
Ini salah satu pertanyaan paling penting.
Misalnya:
class A {
A() {
print("Constructor A");
}
}
class B extends A {
}
Orang mungkin berpikir:
“Karena B extends A, berarti constructor A juga masuk ke B.”
Tetapi constructor tidak diwariskan sebagai constructor milik subclass.
Kenapa?
Karena constructor berkaitan dengan pembuatan dan inisialisasi object dari class tertentu.
Nama constructor generatif biasanya mengikuti nama class:
A()
adalah constructor untuk A.
Sedangkan:
B()
adalah constructor untuk B.
Kalau constructor A() “diwariskan” menjadi constructor B, identitas constructor tersebut tidak lagi sesuai dengan class yang sedang dibuat.
10. Tapi bagaimana B menggunakan constructor A?
Bukan diwariskan.
B memanggil constructor superclass.
Contoh:
class A {
final int x;
A(this.x);
}
class B extends A {
B(int value) : super(value);
}
Perhatikan:
super(value)
Artinya:
“Saat membuat B, panggil constructor superclass A dengan
value.”
Contoh:
B obj = B(10);
print(obj.x);
Output:
10
Jadi konsepnya:
B()
β
super(...)
β
A(...)
Bukan:
B mewarisi constructor A
11. Inheritance dan private member
Ini bagian yang sangat penting karena Dart memiliki aturan private yang agak berbeda dari Java/C++.
Misalnya:
class A {
int publicValue = 10;
int _privateValue = 20;
}
Kita membuat:
class B extends A {
}
Apakah _privateValue ikut menjadi bagian dari object B?
Secara inheritance, subclass tetap berada dalam inheritance chain dari superclass tersebut.
Tetapi apakah B boleh mengakses identifier _privateValue?
Jawabannya bergantung pada library.
12. Private Dart bukan private class
Dalam Dart:
_privateValue
berarti private pada library.
Bukan:
private hanya untuk class A.
Misalnya file:
a.dart
berisi:
class A {
int publicValue = 10;
int _privateValue = 20;
}
Kemudian:
b.dart
berisi:
import 'a.dart';
class B extends A {
}
Karena B berada di library yang berbeda, B tidak bisa melakukan:
class B extends A {
void show() {
print(_privateValue); // β
}
}
Tetapi:
print(publicValue);
bisa.
13. Bagaimana kalau A dan B berada di library yang sama?
Kalau keduanya berada dalam library yang sama, akses terhadap private identifier dapat dilakukan sesuai aturan library Dart.
Jadi penting sekali:
Dart private
β
library-level privacy
bukan:
class-level privacy
14. Apakah private member “diwariskan”?
Di sini jangan terjebak dengan kalimat:
“Kalau tidak bisa diakses berarti tidak diwariskan.”
Itu dua hal yang berbeda.
Inheritance dan visibility/accessibility adalah konsep berbeda.
Bayangkan sebuah rumah:
Superclass
βββ public room
βββ private room
Subclass berada dalam struktur yang berhubungan dengan superclass.
Tetapi aturan akses menentukan apakah identifier tertentu bisa digunakan dari lokasi tertentu.
Jadi:
Tidak bisa mengakses
_privateValuedari library lain bukan berarti aturan inheritance-nya tiba-tiba hilang.
Yang membatasi adalah visibility private library-level.
15. Apakah setiap class Dart memiliki inheritance?
Secara konsep dasar:
Ya, setiap class Dart mempunyai superclass.
Kalau kamu menulis:
class A {
}
tanpa:
extends Something
bukan berarti A sama sekali tidak punya superclass.
Class tersebut secara default memiliki superclass Object.
Konsepnya:
Object
β
|
A
16. Contohnya bisa dilihat dari Object
Misalnya:
class A {
}
Kemudian:
void main() {
A obj = A();
print(obj.hashCode);
print(obj.runtimeType);
print(obj.toString());
}
Member seperti hashCode, runtimeType, dan toString() berasal dari mekanisme dasar Object/object model Dart.
Jadi:
Object
β
A
17. Ada pengecualian?
Transcript menyebut:
class
Nulladalah satu-satunya class yang tidak mewarisi Object.
Ini adalah bagian yang sebaiknya jangan kamu jadikan aturan utama saat belajar Dart modern.
Yang penting untuk pemrograman sehari-hari:
Class biasa yang kamu buat tanpa
extendsmemiliki superclassObject.
Dan perlu dibedakan:
null
adalah nilai yang menunjukkan tidak adanya object/reference, bukan “object biasa yang kamu gunakan seperti instance Object”.
Jadi jangan membayangkan:
null β sebuah object biasa
18. Apakah inheritance penting dalam Flutter?
Sangat penting.
Contoh yang hampir pasti kamu lihat ketika belajar Flutter:
class MyHomePage extends StatelessWidget {
}
Perhatikan:
extends StatelessWidget
Itu inheritance.
Strukturnya:
StatelessWidget
β
|
MyHomePage
19. Contoh lain di Flutter
Misalnya:
class MyPage extends StatefulWidget {
const MyPage({super.key});
@override
State<MyPage> createState() {
return _MyPageState();
}
}
Di sini:
MyPage
β extends
StatefulWidget
Kemudian:
class _MyPageState extends State<MyPage> {
}
Ini juga inheritance.
Jadi dalam Flutter kamu akan sering bertemu:
extends StatelessWidget
extends StatefulWidget
extends State<MyPage>
20. Tetapi Flutter bukan hanya inheritance
Ini juga penting.
Jangan sampai kamu berpikir:
“Flutter semuanya inheritance.”
Tidak.
Flutter sangat banyak menggunakan composition.
Misalnya:
Scaffold(
appBar: AppBar(
title: Text("Hello"),
),
body: Column(
children: [
Text("Welcome"),
Icon(Icons.home),
],
),
)
Di sini widget disusun dari widget lainnya.
Jadi Flutter banyak menggunakan kombinasi:
Inheritance
+
Composition
+
Mixin
+
Interfaces
21. Apakah belajar extends saja sudah cukup?
Tidak.
Memahami:
class B extends A
baru merupakan dasar inheritance.
Kalau ingin benar-benar memahami OOP dan inheritance di Dart, kamu juga perlu memahami:
Abstract class
abstract class Animal {
}
Abstract method
abstract class Animal {
void makeSound();
}
Interface
Di Dart, setiap class secara konsep dapat digunakan sebagai interface.
class Animal {
void eat() {}
}
class Cat implements Animal {
@override
void eat() {}
}
Mixin
mixin CanFly {
void fly() {}
}
dan:
class Bird with CanFly {
}
Constructor dalam inheritance
Terutama:
super(...)
Method overriding
Misalnya:
class Animal {
void sound() {
print("Animal sound");
}
}
class Cat extends Animal {
@override
void sound() {
print("Meow");
}
}
Ini nantinya membawa kamu ke konsep polymorphism.
22. Apakah class bisa dibuat final?
Transcript mengatakan bahwa Dart tidak bisa membuat class final.
Ini adalah bagian transcript yang sudah tidak sesuai dengan Dart modern.
Dart modern mendukung final class.
Contohnya:
final class A {
}
Kemudian class lain tidak boleh:
class B extends A { } // β
dan juga tidak boleh mengimplementasikan atau menggunakan class tersebut sebagai superclass/interface dengan cara yang melanggar aturan final class.
Jadi sekarang justru ada cara resmi untuk mengatakan:
Class ini tidak boleh diperluas/diperluas lagi oleh library lain.
23. Jangan bingung final class dengan final variable
Ada dua hal berbeda.
Final variable
final int age = 20;
Artinya:
variabel hanya bisa diberi nilai sekali.
Final class
final class User {
}
Artinya:
class tersebut tidak dapat digunakan sebagai superclass oleh class lain.
Jadi:
final variable
β nilai tidak bisa diubah setelah assignment
final class
β tidak boleh diwariskan
Ini dua konsep yang berbeda.
24. Ada juga sealed, base, dan interface
Dart modern memiliki class modifiers yang lebih kaya.
Misalnya:
sealed class Result {
}
Ini berguna untuk membuat hierarchy yang dikontrol dan sangat berguna bersama pattern matching/switch.
Ada juga:
base class
interface class
final class
sealed class
Masing-masing mempunyai aturan inheritance/implementation yang berbeda.
Untuk tahap sekarang, jangan buru-buru menghafal semuanya. Yang paling penting:
extends β inheritance
implements β interface implementation
with β mixin
dan:
final class β tidak boleh dijadikan superclass
25. Inheritance vs Association
Sekarang kita masuk pertanyaan terakhir.
Ada dua hubungan besar:
IS-A
HAS-A
IS-A
Kalau:
class Person {
}
class Employee extends Person {
}
maka:
Employee IS-A Person
Karena:
Employee adalah Person.
Ini inheritance.
26. HAS-A
Misalnya:
class Engine {
}
class Car {
Engine engine = Engine();
}
Kita tidak mengatakan:
Car adalah Engine.
Tetapi:
Car memiliki Engine.
Jadi:
Car HAS-A Engine
Ini bukan inheritance.
Ini relationship melalui object/reference.
27. Association
Association adalah hubungan umum antara dua class.
Misalnya:
class MusicPlayer {
void play() {
print("Playing music");
}
}
class Car {
final MusicPlayer player;
Car(this.player);
}
Ada hubungan:
Car βββββββ> MusicPlayer
Tetapi:
Car extends MusicPlayer
tidak ada.
Jadi:
Car HAS-A MusicPlayer
28. Aggregation
Aggregation adalah bentuk association dengan hubungan/ownership yang relatif lemah.
Contohnya:
Car βββββββ> MusicPlayer
MusicPlayer bisa dibuat dan digunakan sendiri.
MusicPlayer player = MusicPlayer();
Car car = Car(player);
Perhatikan:
MusicPlayer player = MusicPlayer();
dibuat dari luar Car.
Kemudian diberikan:
Car(player)
Ini cocok untuk menggambarkan aggregation.
29. Composition
Composition adalah hubungan yang lebih erat antara whole dan part.
Misalnya:
class Engine {
}
class Car {
final Engine engine = Engine();
}
Car membuat dan memiliki Engine.
Secara desain:
Car
|
βββ Engine
Ini menggambarkan composition.
30. Bedakan dengan inheritance
Lihat tiga contoh berikut.
Contoh 1
class Cat extends Animal {
}
Baca:
Cat adalah Animal.
IS-A
β inheritance.
Contoh 2
class Car {
MusicPlayer player;
}
Baca:
Car memiliki MusicPlayer.
HAS-A
β association.
Contoh 3
class Car {
final Engine engine = Engine();
}
Baca:
Car tersusun/terdiri dari Engine.
β composition secara desain.
31. Tabel perbedaan
| Konsep | Pertanyaan | Contoh |
|---|---|---|
| Inheritance | “Apakah A adalah B?” | Cat IS-A Animal |
| Association | “Apakah A berhubungan dengan B?” | Car β MusicPlayer |
| Aggregation | “A memiliki B, tetapi B relatif independen?” | Car β MusicPlayer |
| Composition | “A memiliki B dengan ownership/lifecycle erat?” | Car β Engine |
32. Contoh gabungan
Supaya lebih jelas, kita buat satu program.
class Vehicle {
void move() {
print("Vehicle is moving");
}
}
class Engine {
void start() {
print("Engine started");
}
}
class Car extends Vehicle {
final Engine engine = Engine();
void startCar() {
engine.start();
move();
}
}
Sekarang ada dua relationship sekaligus.
Relationship pertama
class Car extends Vehicle
Artinya:
Car IS-A Vehicle
β inheritance.
Relationship kedua
final Engine engine = Engine();
Artinya:
Car HAS-A Engine
β composition secara desain.
Jadi sebuah class bisa memiliki beberapa jenis hubungan dengan class lainnya.
33. Hal penting: inheritance bukan sekadar “reuse code”
Ini perlu kamu pahami sebelum lanjut ke polymorphism.
Inheritance memang bisa digunakan untuk reuse code, tetapi tujuan utama inheritance seharusnya juga mencerminkan hubungan tipe yang benar.
Misalnya:
class Car extends Engine
mungkin bisa saja membuat method Engine tersedia di Car, tetapi secara konsep:
Car adalah Engine?
Tidak masuk akal.
Lebih tepat:
class Car {
Engine engine = Engine();
}
Karena:
Car memiliki Engine.
Jadi jangan memilih inheritance hanya karena:
“Saya ingin menggunakan method dari class tersebut.”
Pertanyaan pertama harus:
Apakah hubungan kedua class memang IS-A?
Kalau tidak, mungkin composition/interface/mixin lebih cocok.
34. Cara cepat menjawab soal inheritance
Kalau nanti kamu mendapat soal seperti:
class Dog extends Animal
tanyakan:
Siapa parent?
Animal
Siapa child?
Dog
Apa hubungannya?
Dog IS-A Animal
Keyword?
extends
Kalau:
class Car {
Engine engine = Engine();
}
tanyakan:
Apakah Car adalah Engine?
Tidak.
Apakah Car memiliki Engine?
Ya.
Maka:
HAS-A
dan bukan inheritance.
35. Ringkasan 10 pertanyaan
Sekarang kita rangkum seluruh video.
1. Mengapa tidak ada multiple inheritance?
Karena Dart tidak mendukung satu class memiliki beberapa superclass langsung melalui extends. Salah satu masalah yang dihindari adalah ambiguity/diamond problem.
class C extends A, B // β
2. Mengapa panah inheritance ke atas?
Karena diagram UML/OOP umumnya menggambarkan arah menuju superclass:
Superclass
β
Subclass
3. Mengapa tidak copy-paste?
Karena menyebabkan:
duplicate code
β
kode lebih besar
β
maintenance sulit
β
risiko inkonsistensi
Inheritance memungkinkan behavior yang memang umum digunakan bersama.
4. Mengapa constructor tidak diwariskan?
Karena constructor digunakan untuk membuat dan menginisialisasi instance dari class tertentu.
Subclass dapat memanggil constructor superclass menggunakan:
super(...)
tetapi tidak mewarisinya sebagai constructor subclass.
5. Bagaimana private member?
Dart menggunakan _ untuk private pada library level.
int _age;
Bukan private khusus class.
6. Apakah semua class punya inheritance?
Class biasa yang tidak menentukan superclass secara eksplisit memiliki Object sebagai superclass.
class A {}
secara konsep:
Object
β
A
7. Apakah inheritance penting di Flutter?
Ya.
Contoh:
class MyWidget extends StatelessWidget
dan:
class MyPage extends StatefulWidget
Inheritance sangat penting dalam memahami API Flutter.
8. Apakah extends saja cukup?
Tidak.
Kamu juga perlu memahami:
abstract class
abstract method
interface
implements
mixin
with
constructor inheritance
super
overriding
polymorphism
9. Apakah class bisa dibuat final?
Di Dart modern: bisa.
final class User {
}
Class lain tidak boleh mewarisinya.
10. Apa bedanya inheritance, aggregation, composition?
Paling gampang:
IS-A
β
Inheritance
β
extends
sedangkan:
HAS-A
β
Association
β
Aggregation / Composition
36. Peta konsep yang harus kamu hafalkan
CLASS RELATIONSHIP
β
ββββββββββββββ΄βββββββββββββ
β β
IS-A HAS-A
β β
INHERITANCE ASSOCIATION
β β
extends ββββββββ΄βββββββ
β β β
ββββββββ΄βββββββ Aggregation Composition
β β β
Single Multi- Hierarchical
level
Dan dalam Dart:
extends
β
Inheritance
β
IS-A
object/reference
β
Association
β
HAS-A
with
β
Mixin / reuse behavior
implements
β
Interface implementation
π§ Kalimat yang paling penting dari materi ini
Kalau kamu hanya mau mengingat beberapa hal dari video ini, ingat 5 kalimat berikut:
- Inheritance = hubungan IS-A.
- Association = hubungan HAS-A.
- Dart tidak mendukung multiple inheritance melalui
extends. - Constructor superclass tidak diwariskan, tetapi dapat dipanggil dengan
super(...). final classdi Dart modern dapat digunakan untuk mencegah class diwariskan.
Dan satu hal yang sangat penting untuk perjalananmu belajar Flutter:
extends
β
inheritance
β
superclass / subclass
β
overriding
β
polymorphism
β
abstract class / interface
β
mixin
Jadi setelah memahami video ini, fondasi berikutnya yang sangat bagus untuk dipelajari adalah super, method overriding, @override, abstract class, interface (implements), dan polymorphism, karena konsep-konsep tersebut merupakan kelanjutan langsung dari inheritance.