Flutter'da Miras Meselesinin 3 Atlısı

Dart'ta bir sınıf başka bir sınıfı miras alabilir. Bunu yapmak için de 3 anahtar kelimeyi kullanır. Bunları aşağıdaki gibi listeleyebiliriz.

extends:

extends anahtar sözcüğü, tipik OOP (Nesne Yönelimli Programlama) özellikleri olan Soyutlama (Abstraction), Kapsülleme (Encapsulation), Miras Alma (Inheritance) ve Çok Biçimlilik (Polymorphism) özelliklerinden Miras Alma/Kalıtım (Inheritance)'yı karşılar.

Bir sınıf, başka bir sınıfı genişletiyorsa (extends), miras alınan sınıftaki tüm özellikler (properties), değişkenler (variables), yöntemler (methods) miras alan sınıfta da mevcuttur. Ayrıca, yöntemleri geçersiz (override methods) kılabilirsiniz.

first_class.dart (Bkz. first_class.dart)

class FirstClass {
  static String valueString = "Extends Test";

  void firstClassFunc() {
    print('firstClassFunc');
  }
}

second_class.dart (Bkz. second_class.dart)

import 'package:dart_extends_with_implements/first_class.dart';

class SecondClass extends FirstClass {}

main.dart (Bkz. main.dart)

  // First Class Örneğini Oluştur
  var firstClass = FirstClass();

  // firstClassFunc() çağırılıyor
  firstClass.firstClassFunc();

  // FirstClass sınıfının statik değişkeni yazdırılıyor
  print(FirstClass.valueString);

  // Second Class Örneğini Oluştur
  var secondClass = SecondClass();

  // Miras alınan firstClassFunc() çağırılıyor.
  secondClass.firstClassFunc();

Kodumuzu çalıştırdığımızda, elde edeceğimiz çıktı aşağıdaki gibi olacaktır.

Çıktı

flutter: firstClassFunc
flutter: Extends Test
flutter: firstClassFunc

Bkz. Extending a class

implements:

Bildiğiniz gibi Dart dilinde her sınıf ancak tek bir sınıftan miras alabilir. Eğer birden fazla sınıftan miras almak istiyor ve çoklu kalıtım sağlamak istiyorsanız, extends (Kalıtım/Miras Alma) konusunu açıklarken, çoklu kalıtım ile ilgili ihtiyacın giderilmesi için literatürdeki Arayüz (Interface) kavramı ortaya çıktığını belirtmiştik.

Ancak gel gelelim Dart dilinde interface kavramı yoktur. İşte tam da bu noktada implements anahtar kelimesi devreye girer. Her sınıf extends anahtar kelimesi ile sadece tek bir sınıftan miras alabiliyorken, implements anahtar kelimesi ile birden fazla sınıf implemente edilebilir ve bu sayede çoklu kalıtım desteklenmiş olur.

third_class.dart (Bkz. third_class.dart)

class ThirdClass {
  void thirdClassFunc() {
    print('thirdClassFunc');
  }
}

fourth_class.dart (Bkz. fourth_class.dart)

import 'package:dart_extends_with_implements/third_class.dart';

class FourthClass implements ThirdClass {
  @override
  void thirdClassFunc() {
    print(
        'Uygulanan ThirdClass sınıfının yöntemlerini bildirmek zorunda kaldık');
  }
}

main.dart (Bkz. main.dart)

  // Third Class Örneğini Oluştur
  var thirdClass = ThirdClass();

  // thirdClassFunc() çağırılıyor
  thirdClass.thirdClassFunc();

  // Fourth Class Örneğini Oluştur
  var fourthClass = FourthClass();

  // Implemente edilen sınıfın fonksiyonu override ediliyor.
  fourthClass.thirdClassFunc();

Kodumuzu çalıştırdığımızda, elde edeceğimiz çıktı aşağıdaki gibi olacaktır.

Çıktı

flutter: thirdClassFunc
flutter: Uygulanan ThirdClass sınıfının yöntemlerini bildirmek zorunda kaldık

Dart dilinde arayüz/interface kavramının bulunmadığını, buna karşılık implements anahtar kelimesi ile birden fazla sınıf implemente edilebileceğini belirtmiştik.

Örneğimizde de olduğu gibi ThirdClassFourthClass'ına implemente ediliyor. extends işleminden farklı olarak FourthClass içerisinde ThirdClass'a ait thirdClassFunc metodu zorunlu olarak override ediliyor. Bu özelliği ile soyut sınıflarla (abstract classes) benzerlik göstermektedir.

Peki, farkı nedir?

Bir soyut sınıf (abstract class) hem soyut hem de somut metotlar içerebilir. Ancak soyut sınıf (abstract class) başka bir sınıfa extends edildiğinde sadece soyut metotları zorunlu olarak eklenirken, implements ile implemente edilirse hem hem soyut hem de somut metotlar zorunlu olarak eklenir.

Bkz. implicit-interfaces

with:

Dart resmi dokümantasyonunda "Mixin'ler, bir sınıfın metotlarını birden çok sınıf (multiple class) hiyerarşisinde yeniden kullanmanın bir yoludur." şeklinde tanımlanır. En basit haliyle de ancak bu şekilde tanımlanabilir. Bir mixin, with anahtar sözcüğünü ile kullanılır.

Aşağıdaki örneğimizle FiveClass ve SixClass isimli sınıflarımızı mixin olarak oluşturuyoruz.

five_class.dart (Bkz. five_class.dart)

mixin FiveClass {
  void fiveClassFunc(){
    print('fiveClassFunc');
  }
}

six_class.dart (Bkz. six_class.dart)

mixin SixClass {
  void number() {
    print(100);
  }
}

SevenClass isimli sınıfımıza with anahtar kelimesiyle FiveClass ve SixClass isimli mixin'lerimizi ekliyoruz. Burada hatırlamamız gereken iki unsur var. Birincisi; with anahtar kelimesi ile eklediğiniz sınıfların metotlarını kullanabilir ve üst sınıfın metotlarını geçersiz kılabilirsiniz. İkincisi; with ile eklediğiniz mixin'lerin metotlarını zorunlu olarak eklemenize ihtiyaç yoktur. Hangilerini ezmek istiyorsanız onları ekleyebilirsiz.

seven_class.dart (Bkz. seven_class.dart)

import 'package:dart_extends_with_implements/six_class.dart';
import 'package:dart_extends_with_implements/five_class.dart';

class SevenClass with FiveClass, SixClass {
  @override
  void fiveClassFunc() {
    print('Gerekirse geçersiz kılabilir');
  }
}

main.dart (Bkz. main.dart)

  // Seven Class Örneğini Oluştur
  var sevenClass = SevenClass();

  // fiveClassFunc() çağırılıyor
  sevenClass.fiveClassFunc();

  // number() çağırılıyor
  sevenClass.number();

Kodumuzu çalıştırdığımızda, elde edeceğimiz çıktı aşağıdaki gibi olacaktır.

Çıktı

flutter: Gerekirse geçersiz kılabilir
flutter: 100

Bkz. Adding features to a class: mixins

Beyin Jimnastiği

class Sanatci {
   void perform() {
     print('performing...');
   }
}

mixin Dansci {
   void perform() {
     print('Dance...Dance...Dance..');
   }
}

mixin Sarkici {
   void perform() {
     print('lalaaa..laaalaaa....laaaaa');
   }
}

class Muzisyen extends Sanatci with Dansci, Sarkici {
   void showTime() {
     perform();
   }
}

void main() {
  var muzisyen = Muzisyen();
  muzisyen.showTime();
}

Çıktısı ne olur? Neden?

Mixin ile "on" Anahtar Kelimesi

On anahtar sözcüğü, Mixin'in kullanımını yalnızca bildirildiği sınıfı genişleten (extend eden) veya uygulayan (implements) sınıflarla sınırlamak için kullanılır.

Nasıl kullanıldığını anlamak için On anahtar sözcüğünü kullandığımız aşağıdaki örneğe bir göz atalım.

class A {
  void show() {
     print('ClassA...');
  }
}

class B{
  void show() {
     print('ClassB...');
  }
}

mixin X on A{
  void show() {
     print('MixinX...');
  }
}

mixin Y on B {
  void show() {
     print('MixinY...');
  }
} 

class P extends A with X {}
class Q extends B with Y {}

void main() {
  var p = P();
  p.show();
}

Örneğimizi çalıştırdığımızda çıktısı aşağıdaki gibi oluşacaktır.

MixinX...

Peki örneğimizdeki P sınıfını aşağıdaki satır ile değiştirirsek çıktımız nasıl değişir?

class P with X {}

Elbette hata alacağız..

Çünkü, X mixin'i oluştururken "on" anahtar kelimesi ile A sınıfı ile gelişletilmesini zorunlu hale getirmiş olduk. Dolayısı ile P sınıfı, A sınıfı extend edilmeden, X mixin'ini implemente edemez.

Egemen MEDE - 25.09.2022