skip to Main Content
Jenerikler(Generics)

Jenerikler(Generics)

Türkçe’ye jenerik ya da genel türler şeklinde çevrilen kavram tür bağımsız ifadeleri açıklar. Yazmış olduğumuz sınıfların, fonksiyonların vb., belli bir türe göre değil, her türe göre çalışmasını sağlamaktadır. Örneğin String, int, Araba (özel sınıf) vb. her şey birer jenerik tür olabilir. Bu türü ihtiyaca göre siz belirlersiniz. Ama belirlemek zorunda değilsiniz. Tür belirlemezseniz dart dili otomatik olarak türü dynamic olarak belirler.

Aslında program yazarken jenerik tipleri farkına varmadan kullanırız. Jenerikler genelde liste yapılarında kullanılır. Dart dilinde kullanılan List<T> sınıfı,  jenerik tür alan sınıftır. Siz sadece öğrenci adlarını içerecek String türünde bir liste tanımlarsınız. O liste artık size isim listesi olarak hizmet eder. Araya sayı veya başka bir ifade ekleyemezsiniz. Çünkü türünü belirlediğiniz için derleme anında derleyici size hata verecektir. Bu size tip güvenliği sağlar. Siz burada sadece List sınıfını kullanarak String değerler tutan bir dizi oluşturdunuz. Eğer list sınıfı jenerik türde olmasaydı, List sınıfının aynısının birde int versiyonu olacaktı. Öğrenci numaralarını bir dizi içinde tutmak için bu sınıfı (int versiyonlu) kullanmak zorunda kalacaktınız. Liste sınıfını Object türde eleman içeren  tek bir sınıf yaparak onu kullanmak ise size tür dönüşümlerinde baya sıkıntı çıkaracaktı. List sınıfı jenerik türde olunca gereksiz kod önlendi ve esneklik sağlanmış oldu. 

// Kullanım 1
List<String> name = List();
name.add("İzzet");
name.add("Mehmet");

// Kullanım 2
// Aşağıdaki kullanımda liste elemanları dynamic türe sahiptir.
var name = List(); 
// Bu yanlış bir kod değildir fakat kötü bir kullanımdır. Liste kümesindeki elemanların türü belirtilmelidir.

Yukarıdaki Kullanım 2 de tüm liste elemanları dynamic türde olduğu için, liste elemanına eklediğiniz türün kendi özel fonksiyonlarını kullanamazsınız. Örneğin String türünün length adında, o değişkenin uzunluğunu size veren bir fonksiyonu vardır. Fakat dynamic türünde böyle bir fonksiyon size sunulmaz. Bu şekilde olunca, dynamic olan veriyi önce String türüne dönüştürüp, sonra onun altındaki özellikleri kullanırız. Bu zahmetli bir iştir. Gelecek olan türleriniz belli ise, her zaman değişken tanımlamalarınızda tür belirtmeniz sizin için faydalı olacaktır.

// Kullanım 1
List<String> name = List();
name.add("İzzet");
name.add("Mehmet");
print(name[0].length); // Çıktı: 5

// Kullanım 2
var name = List();
name.add("İzzet");
print(name[0].length); // Derleme hatası

Aşağıdaki genel bir örnek ile bu konuyu daha iyi kavrayacağınıza inanıyorum. Örneğin bir sınıfımız olsun ve bu sınıfın bir yazdırma fonksiyonu olsun. Ben bu sınıfa türü ne olursa olsun bir değer gönderdiğimde değerimi ekrana yazdırsın.

class WriteGeneric<T> {
  final T obj;
  
  WriteGeneric(this.obj);
  
  void printObj() {
    print(obj);
  }
}

// Kullanım
var intGeneric = WriteGeneric(3);
var doubleGeneric = WriteGeneric(1.2);
var stringGeneric = WriteGeneric("İzzet");
var boolGeneric = WriteGeneric(true);

intGeneric.printObj(); // Çıktı: 3
doubleGeneric.printObj();// Çıktı: 1.2
stringGeneric.printObj();// Çıktı: İzzet
boolGeneric.printObj();// Çıktı: true

Yukarıdaki örnekte jenerik sınıf, bir tür ile sınırlandırılmamıştır. print sistem fonksiyonu tüm verileri yazdırabildiği için sıkıntı çıkmamıştır. Fakat oraya özel bir sınıf gönderdiğimizde çıktı olarak değişkenin tüm değerlerini göremeyiz. Böyle durumları ortadan kaldırmak için genelde generic sınıflar temel bir tür ile sınırlandırılır. Ve diğer sınıflar bu temel sınıftan türetilir. Böylece tüm sınıflar da aynı fonksiyon mevcut olacaktır.

abstract class Document {
  void printType();
}

class Pdf implements Document {
  @override
  void printType() {
    print("Pdf Document");
  }
}

class Word implements Document {
  @override
  void printType() {
    print("Word Document");
  }
}

class WriteGeneric<T> {
  final T obj;
  WriteGeneric(this.obj);
  
  void printDocumentType() {
    obj.printType();
  }
}

// Kullanımı
Pdf pdf = Pdf();
Word word = Word();
var writePdfDocument = WriteGeneric<Pdf>(pdf);
var writeWordDocument = WriteGeneric<Word>(word);

writePdfDocument.printDocumentType(); // Çıktı: Pdf Document
writeWordDocument.printDocumentType(); // Çıktı: Word Document
This Post Has One Comment
  1. Ufak bir düzeltme:
    WriteGeneric sınıfı, class WriteGeneric şeklinde olmalıdır. Aksi takdirde printType() methodunu bilemez.
    Kolay gelsin.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir