Dart Sealed Classes

sealed class adalah fitur baru yang diperkenalkan di Dart 3. Secara sederhana, sealed class adalah sebuah kelas abstrak yang memiliki himpunan subclass yang telah ditentukan, dan semua subclass tersebut harus dideklarasikan di dalam library (file .dart) yang sama dengan sealed class itu sendiri.

Tujuan utama dari sealed class adalah untuk membuat hierarki kelas yang “tertutup” atau “terbatas”. Artinya, kita hanya bisa membuat subclass dari kelas sealed di lokasi yang sama dengan kelas tersebut. Ini mencegah developer lain (terutama dari package lain) membuat subclass baru dari kelas sealed Anda.

Kapan menggunakan sealed class? Anda harus menggunakan sealed class saat kita memiliki kelas yang merepresentasikan status atau varian yang terbatas dan saling eksklusif. Contoh klasik adalah status koneksi jaringan atau hasil dari sebuah operasi asinkron.

Keunggulan Utama sealed class

  1. Kontrol Hierarki: kita memegang kendali penuh atas subclass yang diizinkan, mencegah penambahan subclass yang tidak terduga di luar library Anda.
  2. Pengecekan Komprehensif (Exhaustive Checking): Ini adalah fitur yang paling powerful dari sealed class. Ketika kita menggunakan switch atau if pada objek sealed class, Dart akan secara otomatis memeriksa apakah kita telah menangani semua kemungkinan subclass. Jika ada yang terlewat, analyser (bagian dari IDE yang memeriksa kode) akan memberikan peringatan atau error. Ini menjamin kode kita lebih aman dan tidak akan gagal karena kasus yang tidak terduga.
  3. Tidak Perlu Klausa default: Karena Dart tahu bahwa semua subclass sudah tercakup, kita tidak perlu lagi menggunakan klausa default pada switch. Ini membuat kode lebih bersih dan lebih aman.

Contoh Penggunaan Sealed Class

sealed class Vehicle {
  void startEngine() {
    print("Engine started");
  }

  void stopEngine() {
    print("Engine stopped");
  }
}

// Hanya class di file ini yang boleh extends/implements/mixin Vehicle
class Car extends Vehicle {
  @override
  void startEngine() {
    print("Car engine started");
  }
}

class Bike extends Vehicle {
  @override
  void startEngine() {
    print("Bike engine started");
  }
}

void main() {
  var myCar = Car();
  myCar.startEngine();
  myCar.stopEngine();

  var myBike = Bike();
  myBike.startEngine();
  myBike.stopEngine();
}

Jika kita jalankan maka akan seperti berikut

$ dart run SealedClass.dart 
Car engine started
Engine stopped
Bike engine started
Engine stopped

Perbedaan dengan Final dan Interface Class

  • final class: Tidak bisa diwarisi sama sekali.
  • sealed class: Hanya bisa diwarisi di file yang sama.
  • interface class: Hanya bisa diimplementasikan, tidak bisa diinstansiasi langsung.

Sample source code bisa di download di github pada link berikut dart-tutorial

hyvercode

Dart Final Classes

final class adalah fitur di Dart yang digunakan untuk mencegah class tersebut diwarisi (extends) atau diimplementasikan (implements) oleh class lain. Artinya, class yang dideklarasikan dengan kata kunci final hanya bisa digunakan secara langsung, tidak bisa menjadi parent class

Buat file dengan nama FinalClass.dart

final class vehile {
  void startEngine() {
    print("Engine started");
  }

  void stopEngine() {
    print("Engine stopped");
  }
}

// Extending the final class error canont be extended
class Car extends vehile {
  @override
  void startEngine() {
    super.startEngine();
  }

  @override
  void stopEngine() {
    super.stopEngine();
  }
}

// Impelement the final class error canont be extended
class Bike implements vehile {
  @override
  void startEngine() {
    print("Bike engine started");
  }

  @override
  void stopEngine() {
    print("Bike engine stopped");
  }
}

void main() {
  var myCar = Car();
  myCar.startEngine();
  myCar.stopEngine();

  var myBike = Bike();
  myBike.startEngine();
  myBike.stopEngine();
}

Ketika kita jalankan maka akan terjadi error seperti berikut :

$ dart run FinalClass.dart 
FinalClass.dart:12:7: Error: The type 'Car' must be 'base', 'final' or 'sealed' because the supertype 'vehile' is 'final'.
Try adding 'base', 'final', or 'sealed' to the type.
class Car extends vehile {
      ^
FinalClass.dart:25:7: Error: The type 'Bike' must be 'base', 'final' or 'sealed' because the supertype 'vehile' is 'final'.
Try adding 'base', 'final', or 'sealed' to the type.
class Bike implements vehile {

Penjelasan Kode: Interface Class di Dart

Pada contoh di atas, vehile adalah sebuah final class.

Kenapa Terjadi Error?

1. Mencoba Extends Final Class, Kode di atas akan error karena vehile adalah final class, sehingga tidak boleh diwarisi oleh class lain.

2. Mencoba Implements Final Class, Begitu juga saat mencoba mengimplementasikan final class.

Tujuan Final Class

  • Keamanan kode: Mencegah perubahan perilaku class yang tidak diinginkan melalui pewarisan.
  • Optimasi: Compiler bisa melakukan optimasi lebih baik karena tahu class tersebut tidak akan diwarisi.
  • Desain API: Cocok untuk class yang memang tidak boleh diubah perilakunya oleh developer lain.

Kesimpulan

  • Gunakan final class jika ingin membuat class yang tidak boleh diwarisi atau diimplementasikan.
  • Jika mencoba mewarisi atau mengimplementasikan final class, akan muncul error dari Dart.

Untuk memanggil atau menggunakan final class di Dart, kita tidak bisa mewarisi (extends) atau mengimplementasikan (implements) class tersebut.
Namun, kita tetap bisa membuat objek langsung dari final class dan memanggil method-method yang ada di dalamnya.

Contoh Penggunaan Final Class

final class Vehicle {
  void startEngine() {
    print("Engine started");
  }

  void stopEngine() {
    print("Engine stopped");
  }
}

void main() {
  var myVehicle = Vehicle(); // Membuat objek langsung dari final class
  myVehicle.startEngine();   // Memanggil method
  myVehicle.stopEngine();
}

Sample source code bisa di download di github pada link berikut dart-tutorial

hyvercode

Dart Interface Classes

Dalam Dart, untuk mebuat calss interface dalam dart kita bisa mengunakan kata kunci interface. Meskipun pada dart, setiap class secara implisit adalah sebuah interface. Ini berarti kita dapat menggunakan kata kunci implements pada sebuah class untuk mengimplementasikan interface dari class lain.

  • Ketika sebuah class mengimplementasikan sebuah interface, ia harus menyediakan implementasi (body) untuk semua properti dan method dari interface tersebut.
  • Ini berguna untuk memastikan sebuah class memenuhi “kontrak” tertentu, tanpa perlu mewarisi implementasinya.

Buat file dengan nama InterfaceClass.dart

interface class vehicle {
  void startEngine() {
    print("Engine started");
  }

  void stopEngine() {
    print("Engine stopped");
  }
}

// Extending the interface class
class Car extends vehicle {
  @override
  void startEngine() {
    super.startEngine();
  }

  @override
  void stopEngine() {
    super.stopEngine();
  }
}

// Another class implementing the interface class
class Bike implements vehicle {
  @override
  void startEngine() {
    print("Bike engine started");
  }

  @override
  void stopEngine() {
    print("Bike engine stopped");
  }
}

// Main function to demonstrate the usage
void main() {
  print("Interface Class Extends:");
  var myCar = Car();
  myCar.startEngine();
  myCar.stopEngine();

  print("Interface Class Implements:");
  var myBike = Bike();
  myBike.startEngine();
  myBike.stopEngine();
}

Contoh Output:

$ dart run InterfaceClass.dart
Interface Class Extends:
Engine started
Engine stopped
Interface Class Implements:
Bike engine started
Bike engine stopped

Penjelasan Kode: Interface Class di Dart

1. Interface Class vehicle

interface class vehicle {
  void startEngine() {
    print("Engine started");
  }

  void stopEngine() {
    print("Engine stopped");
  }
}
  • interface class adalah fitur baru di Dart yang memungkinkan sebuah class hanya bisa di-extend atau di-implement oleh class lain, tapi tidak bisa di-instansiasi langsung.
  • Pada contoh di atas, vehicle mendefinisikan dua method: startEngine() dan stopEngine(), yang masing-masing mencetak pesan ke konsol.

2. Extending Interface Class: Car

class Car extends vehicle {
  @override
  void startEngine() {
    super.startEngine();
  }

  @override
  void stopEngine() {
    super.stopEngine();
  }
}
  • Car adalah class yang mewarisi (extends) dari vehicle.
  • Method startEngine() dan stopEngine() di-override untuk menunjukkan bahwa class turunan bisa mengubah atau menambah perilaku dari method parent-nya.
  • Pada contoh ini, method hanya memanggil method dari parent (super.startEngine()), tapi bisa dikembangkan sesuai kebutuhan.

3. Implementasi Lain: Bike

class Bike extends vehicle {
  @override
  void startEngine() {
    super.startEngine();
  }

  @override
  void stopEngine() {
    super.stopEngine();
  }
}

Bike juga mewarisi dari vehicle dan meng-override kedua method dengan cara yang sama seperti Car.

4. Fungsi Main

void main() {
  var myCar = Car();
  myCar.startEngine();
  myCar.stopEngine();

  var myBike = Bike();
  myBike.startEngine();
  myBike.stopEngine();
}
  • Pada fungsi main, objek Car dan Bike dibuat.
  • Setiap objek memanggil method startEngine() dan stopEngine(), sehingga akan mencetak pesan ke konsol.

Kesimpulan

  • interface class di Dart sangat berguna untuk membuat kontrak perilaku yang harus diikuti oleh class turunan.
  • Tidak bisa membuat objek langsung dari vehicle, tapi bisa membuat objek dari class turunannya (CarBike).
  • Cocok digunakan untuk arsitektur aplikasi yang membutuhkan konsistensi perilaku pada beberapa class turunan.

Sample source code bisa di download di github pada link berikut dart-tutorial

hyvercode

TypeScript Class

Basic Class

TypeScript sama seperti ECMA Script 6 (ES6), support object-oriented programing (OOP). Class sendiri adalah sebuah blueprint atau rancangan untuk membuat objek dengan properti dan metode tertentu. Class dapat digunakan untuk membuat objek dengan karakteristik dan perilaku yang serupa.

Dalam class, kita dapat menentukan properti atau variabel yang dimiliki oleh objek dan metode atau fungsi yang dapat dijalankan pada objek. Class juga dapat memiliki constructor, yang digunakan untuk menginisialisasi properti ketika sebuah objek dibuat.

Berikut contoh sederhana class di TypeScript:

// Sample class Animal
class Animal {
    name:string;
    foot:number;

    constructor(name: string,foot:number){
        this.name = name;
        this.foot = foot;
    }

    printAnimal(){
        console.log(`Animal name ${this.name} number of animal legs ${this.foot}`)
    }
}

let tiger = new Animal("Tiger",4);

tiger.printAnimal();


let chicken = new Animal("Chicken",2);

chicken.printAnimal();
$ ts-node Animal.ts
Animal name Tiger number of animal legs 4
Animal name Chicken number of animal legs 2

Pada contoh diatas kita membuat sebuah class dengan nama class Animal dimana classs yang memiliki properti nama dan kaki selain itu class Animal juga memiliki function/methode printAnimal(), dimana function ini akan digunakan untuk mecetak nama dan jumlah kaki dari animal. Classs Animal ini adalah Blueprint dimana dengan class ini kemudian kita membuat object Tiger. Object tiger di buat instance dari class Animal dimana ketika kita membuat object tiger kita mengirim paramater ke contructor Animal yaiu name = “Tiger” dan foot = 4, selain tiger kita juga membuat object Chicken dengan nama=”Chicken” dan foot=2. Jadi dengan satu class Animal kita bisa membuat beberapa object lainnya dengan paramater yang berbeda.

Contructors

Contructor adalah sebuah method khusus yang dieksekusi ketika sebuah instance objek dibuat dari class. Constructor digunakan untuk menginisialisasi nilai properti dalam objek yang dibuat. Dalam sebuah class, constructor dapat dideklarasikan dengan menggunakan keyword “constructor”

Contoh pengunaan Contructor di TypeScript :

class Animal {
    name:string;
    foot:number;

    constructor(name: string,foot:number){
        this.name = name;
        this.foot = foot;
    }

    printAnimal(){
        console.log(`Animal name ${this.name} number of animal legs ${this.foot}`)
    }
}

Atau kita bisa juga membuat contructor lebih sederhana seperti berikut :

class Animal {
    constructor(public name: string,public foot:number){
        this.name = name;
        this.foot = foot;
    }

    printAnimal(){
        console.log(`Animal name ${this.name} number of animal legs ${this.foot}`)
    }
}

Source code tutorial Typescript tersedia di github typescript-days

hyvercode

Dart Abstract Classes

Abstract Class , adalah class yang tidak bisa dibuat object Karena masih bersifat abstract, Abstract class memiliki method yang juga bersifat abstract atau belum memiliki implentasinya. Untuk membuat abstract class yaitu dengan menggunakan keyword abstract contoh pembuatan abstract class :

abstract class car{
  void onRun()
}

untuk membuat implementasi dari sebuah abstract class maka kita bisa embuât class implementatornya seperti berikut:

abstract class Car{
  void onRun();
  void onBreak();
}

class Truck implements Car{
  @override
  void onRun() {
    // TODO: implement onRun
    print("Truck run");
  }

  @override
  void onBreak() {
    // TODO: implement onBreak
    print("Truck on break");
  }

}

class Bus implements Car{
  @override
  void onBreak() {
    // TODO: implement onBreak
    print("Bus on break");
  }

  @override
  void onRun() {
    // TODO: implement onRun
    print("Bus on run");
  }

}

void main(){
  var truck = new Truck();
  truck.onRun();
  truck.onBreak();

  var bus = new Bus();
  bus.onRun();
  bus.onBreak();

}
//output

Truck run
Truck on break
Bus on run
Bus on break

Sample source code bisa di download di github pada link berikut dart-tutorial

hyvercode

Dart Functions as first-class objects

Kita bisa melakukan parsing paramater dari function ke function lainya contoh :

void main(){
  var list=[1,2,3];
  list.forEach(printElement);
}

void printElement(int element){
  print(element);
}
1
2
3

Sample source code can be downloaded on github at the following link    dart-tutorial

hyvercode