Nesne yönelimli programlamada (OOP)’nin temel unsurlarından biri olan Inheritance(kalıtım) bir sınıfın başka bir sınıfın özelliklerini devralmasını sağlar. Böylece kod tekrarını azaltır, esnek bir mimari kurgular ve proje büyüdükçe yönetilebilirliği artar. Miras alınan sınıfın özellik ve metotları üzerinde değişiklikler yapılarak geliştirilebilir yada yeni özellik ve metotlar elde edilebilir.
Bu yazıda, Dart dilinde kalıtımın nasıl çalıştığını, bir örnek üzerinden adım adım inceleyeceğiz.
Hayvan Sınıfı (Superclass)
Tüm hayvanların ortak özelliği olan ad ve yaş bilgisini tutan temel bir sınıf tanımlayalım.
Alt sınıflara özelliklerini devreden bu sınıfa superclass (üst sınıf) denir.
class Hayvan{
String ad;
int yas;
Hayvan({required this.ad, required this.yas});
}Constructor’da required anahtar kelimesini kullanarak ad ve yas değerlerinin nesne oluşturulurken zorunlu olarak verilmesini sağladık.
Sürüngenler Sınıfı (Subclass)
Bir sürüngen, hayvanların tüm özelliklerine sahiptir ancak kendine has özellikleri de içinde barındırır. Üst sınıf özelliklerini alan sınıflara subclass (alt sınıf) denir.
class Surungenler extends Hayvan{
bool zehirliMi;
Surungenler({required this.zehirliMi, required String ad, required int yas})
: super(ad:ad, yas:yas);
}Burada extend Hayvan ifadesi ile Surungenler sınıfından Hayvan sınıfının tüm özelliklerine erişebiliriz. super anahtar kelimesi alt sınıftan gelen verilerin üst sınıfa aktarılmasını sağlar.
Balıklar Sınıfı (Subclass)
Surungenler sınıfında olduğu gibi Baliklar sınıfı da subclass olarak tanımlanır ve extend metodu ile Hayvan sınıfının tüm özelliklerine erişim sağlar.
class Baliklar extends Hayvan{
bool tehlikeliMi;
Baliklar({required this.tehlikeliMi, required String ad, required int yas})
: super(ad:ad, yas:yas);
}
Kalıtımın Kullanımı
Sınıflarımızı tanımladığımıza göre, şimdi bu sınıflardan nesneler türetelim ve aralarındaki özel ilişkileri inceleyelim.
void main(){
var yilan = Surungenler(zehirliMi: true, ad: "Engerek", yas: 3);
print("Adı : ${yilan.ad}");
print("Yaşı : ${yilan.yas}");
print("Zehirli mi?: ${yilan.zehirliMi}");
var kopekBaligi = Baliklar(tehlikeliMi: true, ad: "Köpek Balığı", yas: 7);
print("Adı : ${kopekBaligi.ad}");
print("Yaşı : ${kopekBaligi.yas}");
print("Tehlikeli mi?: ${kopekBaligi.tehlikeliMi}");
}
Ekran Çıktısı:
Adı : Engerek
Yaşı : 3
Zehirli mi?: true
Adı : Köpek Balığı
Yaşı : 7
Tehlikeli mi?: trueMetot Ezme (Method Overriding)
Kalıtım (Inheritance) ile bir alt sınıf, üst sınıfın tüm metotlarını devralır. Ancak bazen alt sınıfın bu metotları kendi ihtiyaçlarına göre yeniden tanımlaması gerekir. İşte bu işleme Overriding denir.
Dart dilinde bir metodu geçersiz kılmak istediğimizde, kodun okunabilirliğini artırmak ve hataları önlemek için @override terimini kullanırız.
Neden Overriding Kullanırız?
Üst sınıfta tanımlanan genel bir davranışın, alt sınıflarda özelleşmesi gerekiyorsa overriding kullanırız. Örneğin; her otomobilin bir yakıt türü vardır ancak bu tür markadan markaya veya modelden modele değişebilir.
class Otomobil {
void yakitTuru(){
print("Tanımlanmadı");
}
}
class Volkswagen extends Otomobil {
// Bu sınıf yakitTuru metodunu ezmedi (override etmedi).
// Dolayısıyla üst sınıftaki (Otomobil) metodu kullanacaktır.
}Yukarıda da görüldüğü gibi superclass olarak Otomobil() ve ona bağlı subclass olarak Volsvagen() sınıflarını tanımlıyoruz. Her aracın ortak özelliği olan yakıt parametresi için yakitTuru() methodunu superclass içerisinde tanımladık.
class Caddy extends Volkswagen {
@override
void yakitTuru() {
print("Dizel");
}
}
class Polo extends Volkswagen {
@override
void yakitTuru() {
print("Benzin");
}
}Volkswagen sınıfına bağlı Caddy() ve Polo() sınıflarını tanımladık. Araçların yakıt türleri farklı olduğundan override methodu ile kendi içlerinde yakitTuru() tanımlamalarını yaptık.
void main(){
var otomobil = Otomobil();
var volkswagen = Volkswagen();
var caddy = Caddy();
var polo = Polo();
otomobil.yakitTuru(); // Kalıtım yok, kendi metoduna erişti.
volkswagen.yakitTuru(); // Kalıtım var, üst sınıfın metoduna erişti.
caddy.yakitTuru(); // Kalıtım var, kendi metoduna erişti.
polo.yakitTuru(); // Kalıtım var, kendi metoduna erişti.
}Ekran Çıktısı:
Yakıt tanımlanmadı
Yakıt tanımlanmadı
Dizel
BenzinSonuç
Bu yazıda Dart dilinde kalıtım (inheritance) kavramını temel OOP prensipleriyle birlikte ele aldık. Üst sınıf (superclass) ve alt sınıf (subclass) ilişkisini örnekler üzerinden inceleyerek, extends ve super anahtar kelimelerinin nasıl çalıştığını gördük. Kalıtım sayesinde ortak özellik ve davranışların tek bir yerde tanımlanabildiğini, böylece kod tekrarının azaldığını ve daha sürdürülebilir bir yapı oluşturulduğunu gözlemledik.
Ayrıca metot ezme (method overriding) konusuna değinerek, alt sınıfların üst sınıftan gelen davranışları kendi ihtiyaçlarına göre nasıl özelleştirebildiğini inceledik. @override kullanımı ile hem kodun okunabilirliğini artırdık hem de nesne yönelimli tasarımın esnekliğini net bir şekilde ortaya koyduk.
Sonuç olarak, Dart’ta kalıtım ve overriding doğru kullanıldığında daha modüler, genişletilebilir ve bakımı kolay uygulamalar geliştirmek mümkün hale gelir. Özellikle büyük ölçekli projelerde bu yapıların bilinçli bir şekilde kullanılması, yazılım mimarisinin yönetilebilir olmasını sağlar.