Apa itu Mixins
Mixin merupakan cara penggunaan ulang kode, memungkinkan kode dipakai kembali pada hierarki kelas yang tidak saling berkaitan. Tujuannya untuk memberikan implementasi anggota secara massal ke banyak kelas. Secara sekilas mirip pewarisan ganda, namun fungsinya hanya menambahkan modul fitur tertentu ke sebuah kelas.
Menggunakan Mixin
Gunakan kata kunci with, diikuti satu atau lebih nama Mixin.
class Musician extends Performer with Musical {
// kode
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Code language: Dart (dart)
Mendeklarasikan Mixin
Gunakan kata kunci mixin untuk mendeklarasikannya.
Tambahan:
mixin class(Dart 3.0 ke atas) dapat digunakan sekaligus sebagai kelas biasa maupun Mixin.
Aturan Wajib
mixin/mixin classtidak boleh menggunakanextends- tidak diperbolehkan mendeklarasikan konstruktor generatif (generative constructor)
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
class Musician with Musical {}
void main() {
var m = Musician();
m.canConduct = true;
m.entertainMe(); // Waving hands
}
Code language: Dart (dart)
Hasil eksekusi
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingCode language: CSS (css)
Mixin perlu memanggil anggota dari luar
Metode / properti yang tidak dapat didefinisikan di dalam Mixin
Sering kali Mixin perlu memanggil anggota yang tidak diimplementasikannya sendiri. Berikut ada 4 skema standar untuk menangani hal ini.
Mendeklarasikan anggota abstrak di dalam Mixin
Mixin mendeklarasikan metode abstrak, semua kelas yang menggunakan Mixin ini wajib mengimplementasikan metode abstrak tersebut.
mixin Musician {
// Metode abstrak, wajib diimplementasikan pengguna
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
// Pengguna wajib menulis ulang implementasi
class Virtuoso with Musician {
@override
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
void main() {
var artist = Virtuoso();
artist.playPiano();
artist.playFlute();
}
Code language: Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
Mengakses status kelas induk melalui Getter abstrak
Mixin mendeklarasikan getter abstrak untuk membaca field dari kelas induk, sehingga bisa mengakses status antar kelas.
/// Dapat dicampurkan ke kelas apa pun yang memiliki properti name,
/// secara otomatis menyediakan operator == dan hashCode berdasarkan name
mixin NameIdentity {
String get name;
@override
int get hashCode => name.hashCode;
@override
bool operator ==(Object other) =>
other is NameIdentity && name == other.name;
}
class Person with NameIdentity {
final String name;
Person(this.name);
}
void main() {
var p1 = Person("Alice");
var p2 = Person("Alice");
var p3 = Person("Bob");
print(p1 == p2); // true
print(p1 == p3); // false
}
Code language: JavaScript (javascript)
Mixin mengimplementasikan antarmuka implements
Mixin menggunakan implements untuk membatasi antarmuka, memaksa kelas yang menggunakan Mixin melengkapi semua metode antarmuka.
abstract interface class Tuner {
void tuneInstrument();
}
mixin Guitarist implements Tuner {
void playSong() {
tuneInstrument();
print('Strums guitar majestically.');
}
}
class PunkRocker with Guitarist {
@override
void tuneInstrument() {
print("Don't bother, being out of tune is punk rock.");
}
}
void main() {
PunkRocker().playSong();
}
Code language: JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
Klausa on: Membatasi Mixin hanya dapat digunakan oleh subkelas jenis tertentu
Fungsi on: membatasi hanya kelas yang mewarisi tipe yang ditentukan boleh menggunakan Mixin ini.
Selain itu, di dalam Mixin kita bisa memanggil anggota kelas induk dan menjalankan super.xxx().
Gunakan
onhanya jika Anda perlu memanggil metode kelas induk dengansuperdi dalam Mixin!
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// Hanya bisa dicampurkan ke subkelas Musician
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // Bisa memanggil metode induk yang dibatasi klausa on
}
}
// SingerDancer mewarisi Musician, sehingga bisa menggunakan MusicalPerformer
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Code language: Dart (dart)
Performing music!
Playing music!
SingerDancer menggunakan MusicalPerformer, sehingga bisa memakai metode performerMethod di dalamnya.
Cara kerja pencampuran seperti ini: sebuah kelas dapat mengambil metode dari Mixin lain untuk digunakan sendiri.
⚠️ Contoh kesalahan:
Jika sebuah kelas tidak mewarisi
Musicianlalu langsung menuliskanwith MusicalPerformer, kode akan gagal dikompilasi.
Perbedaan class / mixin / mixin class
mixin: hanya dapat dipakai melaluiwith, tidak bisa diwarisi pakaiextendsclass: dapat diwarisi denganextends, tidak bisa langsung digunakan sebagai mixinmixin class:- bisa dipakai sebagai Mixin dengan
with - juga bisa dijadikan induk kelas biasa pakai
extends
- bisa dipakai sebagai Mixin dengan
Aturan yang tetap berlaku:
- mixin / mixin class tidak boleh menggunakan extends, with
- class / mixin class tidak boleh menggunakan on
mixin class Musician {
void play() {
print("Musician is playing");
}
}
// Digunakan sebagai Mixin
class Novice1 with Musician {}
// Digunakan sebagai induk kelas biasa
class Novice2 extends Musician {}
void main() {
Novice1().play();
Novice2().play();
}
Code language: Dart (dart)
Hasil jalankan program
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playing
Code language: CSS (css)
Mixins