Nesne yönelimli programlamada (OOP) sınıflar arası ilişki kurmanın iki temel yolu vardır: kalıtım (inheritance) ve bileşim (composition).
Kalıtım, “bir sınıf diğerinin türüdür” ilişkisini temsil ederken; bileşim, “bir sınıf diğerini içerir” ilişkisini ifade eder.
Dart dilinde composition (bileşim), bir sınıfın işlevselliğini başka bir sınıfı miras almak yerine içinde örnekleyerek (oluşturarak) genişletme yöntemidir. Bu yaklaşım, kodun daha esnek, okunabilir ve yeniden kullanılabilir olmasını sağlar.
Konuyu daha iyi anlamak için bir örnek üzerinden ilerleyelim.
Kitap adı, yazarı, yılı ve kategorisini gösteren bir kod örneği hazırlayacağız. Bunun için Kategoriler, Yazarlar ve Kitaplar olmak üzere üç sınıf oluşturacak ve bu sınıflar arasında composition ilişkisiyle veri okuma işlemi gerçekleştireceğiz.
Kategoriler Tablosu (Sınıfı):

Kategoriler isminde bir sınıf tanımlayalım class Kategoriler{ } .
Bu sınıfın içerisinde ID değerleri için int tipinde kategori_id ve isimler için String tipinde kategori_ad değişkenleri yer alacak.
Değerler daha sonra atanacağı için constructor tanımlayacağız ve required ekleyerek bu değişkenlerin tanımlanmasını zorunlu hale getireceğiz.
Bu durum küçük kod örneklerinde önemsiz gibi görünse de büyük projelerde hataların önüne geçmek için oldukça önemlidir.
class Kategoriler{
int kategori_id;
String kategori_ad;
Kategoriler({required this.kategori_id, required this.kategori_ad});
}Yazarlar Tablosu (Sınıfı):

Kategoriler sınıfındaki yaptığımız işlemlerin aynısını Yazarlar sınıfı içinde gerçekleştirelim.
class Yazarlar { } şeklinde tanımladığımız bu sınıfta, int tipinde yazar_id ve String tipinde yazar_ad değişkenleri bulunacak.
Değerlerin sonradan atanabilmesi için constructor tanımlayacağız ve required anahtar kelimesiyle zorunlu hale getireceğiz.
class Yazarlar{
int yazar_id;
String yazar_ad;
Yazarlar({required this.yazar_id, required this.yazar_ad});
}Kitaplar Tablosu (Sınıfı):

Kitaplar sınıfı, kendine ait verilerin yanı sıra Kategoriler ve Yazarlar sınıflarından da veri okuyacak.
Bu sayede composition yapısını doğrudan uygulamış olacağız.
Sınıf içinde kendine ait değişkenler olarak int tipinde kitap_id ve kitap_yil, ayrıca String tipinde kitap_ad bulunacak.
Bunlara ek olarak Kategoriler ve Yazarlar türünde iki değişken tanımlayacağız ve bu tabloda da değerlerin sonradan atanabilmesi için constructor tanımlayacağız ve required anahtar kelimesiyle zorunlu hale getireceğiz.
class Kitaplar{
int kitap_id;
String kitap_ad;
int kitap_yil;
Kategoriler kategoriler;
Yazarlar yazar;
Kitaplar(
{required this.kitap_id,
required this.kitap_ad,
required this.kitap_yil,
required this.kategoriler,
required this.yazar});
}Bu yapıyla Kitaplar sınıfı, Kategoriler ve Yazarlar sınıflarını içererek (composition) onların özelliklerine erişebilir hale gelir.
Ana Fonksiyon (void main):
Şimdi üç sınıfımız da hazır.
void main() fonksiyonunda örnek veriler oluşturalım ve aralarındaki ilişkiyi görelim.
Kategori :
var kategori1 = Kategoriler(kategori_id: 1, kategori_ad: "Roman");
var kategori2 = Kategoriler(kategori_id: 2, kategori_ad: "Fantastik Kurgu");
var kategori3 = Kategoriler(kategori_id: 1, kategori_ad: "Felsefi Kurgu");Yazarlar :
var yazar1 = Yazarlar(yazar_id: 1, yazar_ad: "Oğuz Atay");
var yazar2 = Yazarlar(yazar_id: 2, yazar_ad: "J.K. Rowling");
var yazar3 = Yazarlar(yazar_id: 1, yazar_ad: "Antoine de Saint");Kitaplar :
var kitap1 = Kitaplar(kitap_id: 1,
kitap_ad: "Tutunamayanlar",
kitap_yil: 1971,
kategoriler: kategori1,
yazar: yazar1);
var kitap2 = Kitaplar(kitap_id: 2,
kitap_ad: "Harry Potter",
kitap_yil: 1997, kategoriler: kategori2,
yazar: yazar2);
var kitap3 = Kitaplar(kitap_id: 3,
kitap_ad: "Küçük Prens",
kitap_yil: 1943,
kategoriler: kategori3,
yazar: yazar3);Kitaplar tablosunda kategoriler: kategori1 , yazar: yazar1 şeklindeki tanımlamada, program okuma işlemi sırasında önce kitaplar tablosuna gidecek; kategoriler isimli değişkene geldiğinde kategoriler1 isimli değişkene giderek Kategoriler Tablosundan kategori_id ve kategori_ad değişkenlerini okuyacak. Aynı şekilde yazar isimli değişkene geldiğinde yazar1 isimli değişkene giderek Yazarlar Tablosundan yazar_id ve yazar_ad değişkenlerini okuyacak.
Okuma işlemlerini daha iyi anlamak için Kitaplar tablosundan veri okuma işlemlerini gerçekleştirelim.
print("Kitap id : ${kitap1.kitap_id}");
print("Kitap ad : ${kitap1.kitap_ad}");
print("Kitap yıl : ${kitap1.kitap_yil}");
print("Kitap kategori : ${kitap1.kategoriler.kategori_ad}");
print("Kitap yazarı : ${kitap1.yazar.yazar_ad}");Kitap kategori ve kitap yazarında görüldüğü gibi kitap1 nesnesi üzerinden doğrudan kategoriler.kategori_ad ve yazar.yazar_ad ifadelerine erişebiliyoruz.
Yani Kitaplar sınıfı, Kategoriler ve Yazarlar sınıflarını içeriyor (composition).
Sonuç
Bu örnekte, composition (bileşim) yapısını kullanarak sınıflar arasında nasıl ilişki kurulabileceğini gördük.
Kalıtım (inheritance) kullanmadan birden fazla sınıf arasında etkileşim sağlamak, daha esnek ve düşük bağımlılıklı (loosely coupled) bir yapı kurmamıza yardımcı olur.
Böylece projelerde kodun bakımı, test edilmesi ve genişletilmesi çok daha kolay hale gelir.
Tam Kod:
class Kategoriler{
int kategori_id;
String kategori_ad;
Kategoriler({required this.kategori_id, required this.kategori_ad});
}
class Yazarlar{
int yazar_id;
String yazar_ad;
Yazarlar({required this.yazar_id, required this.yazar_ad});
}
class Kitaplar{
int kitap_id;
String kitap_ad;
int kitap_yil;
Kategoriler kategoriler;
Yazarlar yazar;
Kitaplar(
{required this.kitap_id,
required this.kitap_ad,
required this.kitap_yil,
required this.kategoriler,
required this.yazar});
}
void main(){
var kategori1 = Kategoriler(kategori_id: 1, kategori_ad: "Roman");
var kategori2 = Kategoriler(kategori_id: 2, kategori_ad: "Fantastik Kurgu");
var kategori3 = Kategoriler(kategori_id: 1, kategori_ad: "Felsefi Kurgu");
var yazar1 = Yazarlar(yazar_id: 1, yazar_ad: "Oğuz Atay");
var yazar2 = Yazarlar(yazar_id: 2, yazar_ad: "J.K. Rowling");
var yazar3 = Yazarlar(yazar_id: 1, yazar_ad: "Antoine de Saint");
var kitap1 = Kitaplar(kitap_id: 1, kitap_ad: "Tutunamayanlar", kitap_yil: 1971, kategoriler: kategori1, yazar: yazar1);
var kitap2 = Kitaplar(kitap_id: 2, kitap_ad: "Harry Potter", kitap_yil: 1997, kategoriler: kategori2, yazar: yazar2);
var kitap3 = Kitaplar(kitap_id: 3, kitap_ad: "Küçük Prens", kitap_yil: 1943, kategoriler: kategori3, yazar: yazar3);
print("Kitap id : ${kitap1.kitap_id}");
print("Kitap ad : ${kitap1.kitap_ad}");
print("Kitap yıl : ${kitap1.kitap_yil}");
print("Kitap kategori : ${kitap1.kategoriler.kategori_ad}");
print("Kitap yazarı : ${kitap1.yazar.yazar_ad}");
print("-" * 35);
print("Kitap id : ${kitap2.kitap_id}");
print("Kitap ad : ${kitap2.kitap_ad}");
print("Kitap yıl : ${kitap2.kitap_yil}");
print("Kitap kategori : ${kitap2.kategoriler.kategori_ad}");
print("Kitap yazarı : ${kitap2.yazar.yazar_ad}");
print("-" * 35);
print("Kitap id : ${kitap3.kitap_id}");
print("Kitap ad : ${kitap3.kitap_ad}");
print("Kitap yıl : ${kitap3.kitap_yil}");
print("Kitap kategori : ${kitap3.kategoriler.kategori_ad}");
print("Kitap yazarı : ${kitap3.yazar.yazar_ad}");
}