Mixins

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

  1. mixin / mixin class tidak boleh menggunakan extends
  2. 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 on hanya jika Anda perlu memanggil metode kelas induk dengan super di 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 Musician lalu langsung menuliskan with MusicalPerformer, kode akan gagal dikompilasi.


Perbedaan class / mixin / mixin class

  1. mixin: hanya dapat dipakai melalui with, tidak bisa diwarisi pakai extends
  2. class: dapat diwarisi dengan extends, tidak bisa langsung digunakan sebagai mixin
  3. mixin class:
    • bisa dipakai sebagai Mixin dengan with
    • juga bisa dijadikan induk kelas biasa pakai extends

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

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *