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 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.
- Alt sınıflar (Child Classes), üst sınıfın (Parent Classes) kurucuları (Constructors) dışındaki tüm özellikleri (properties) ve yöntemleri (methods) devralır.
- Dart, çoklu kalıtımı (Multiple Inheritance) desteklemez. (Çoklu kalıtım (multiple inheritance) bir sınıfın iki veya daha fazla üst sınıftan miras almasını sağlar) Örneğin; Java ve C# çoklu kalıtımı desteklemezken, C++ destekler. C++'ın çoklu kalıtımı desteklemesinden ötürü litaratüre Diamond Problem olarak bilinen sorunu da kazandırmıştır. Bu durumun önüne geçebilmek için ise literatürdeki Arayüz (Interface) kavramı ortaya çıkmıştır.
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
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 ThirdClass'ı FourthClass'ı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
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
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?
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