Kompozisyon vs Kalıtım
Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 47 / 87.
Kalıtım bir "is-a" (bir ...-dır) ilişkisi oluşturur: bir Dog bir Animal'dır. Peki ya bir sınıf, kendisi olmadığı bir şeyden işlevselliğe ihtiyaç duyarsa? İşte burada, bunun yerine bir "has-a" (bir ...-ya sahiptir) ilişkisi kuran kompozisyon (composition) devreye girer.
Kompozisyon ile bir sınıf, diğer sınıfları genişletmek yerine onların örneklerini alan (field) olarak içerir:
// Kalıtım yaklaşımı: Araba bir Motordur (mantıklı değil)
class Car extends Engine { }
// Kompozisyon yaklaşımı: Arabanın bir Motoru VARDIR (mantıklı)
class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.ignite();
}
}Kompozisyon çeşitli avantajlar sunar. Motorları değiştirmek gibi, çalışma zamanında oluşturulan nesneyi değiştirebilirsiniz.
Ayrıca, Java'da kalıtımın izin vermediği bir özellik olan birden fazla sınıftan gelen davranışları birleştirebilirsiniz. Bileşik sınıf, yalnızca kendi seçtiği metotları dışarıya açarak daha iyi bir kapsülleme sağlar.
Pratik bir kural: Gerçek bir "is-a" ilişkisi olduğunda ve alt sınıf (subclass), üst sınıfın (parent) gerçekten özelleşmiş bir versiyonunu temsil ettiğinde kalıtım kullanın.
Başka bir sınıfın işlevselliğini, o türden olmadan kullanmanız gerektiğinde kompozisyonu (composition) kullanın. Pek çok deneyimli geliştirici şu ilkeyi takip eder: "kalıtım yerine kompozisyonu tercih et" çünkü bu, daha esnek ve bakımı kolay kodlar yazılmasını sağlar.
Görev
Kolay"Has-a" (sahip olma) ilişkisini göstermek için kompozisyon kullanarak bir bilgisayar sistemi oluşturalım. Bir Computer sınıfının bileşenlerinden miras alması yerine (ki bu mantıklı olmazdı), bilgisayarınız çalışması için gereken parçaları içerecektir.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
Processor.java: Bir CPU'yu temsil eden bir sınıf oluşturun. Bir Processor iki özel (private) alana sahiptir:brand(String) vespeedGHz(double). Her iki alanı da başlatan bir yapıcı (constructor) ve her biri için getter metotları ekleyin. Şu String değerini döndüren birprocess()metodu ekleyin:[brand] processing at [speedGHz] GHzMemory.java: RAM'i temsil eden bir sınıf oluşturun. Bir Memory iki özel alana sahiptir:type(String, "DDR4" veya "DDR5" gibi) vesizeGB(int). Bir yapıcı, getter metotları ve şu değeri döndüren birload()metodu ekleyin:Loading [sizeGB]GB [type] memoryComputer.java: İşte kompozisyonun parladığı yer burası! Computer sınıfınız, özel alanlar olarak bir Processor ve bir Memory'ye sahip olmalıdır—onları genişletmez (extend), onları içerir. Her iki bileşeni de kabul eden bir yapıcı ekleyin. Bileşenlerini kullanarak bilgisayarın başladığını gösteren çok satırlı bir String döndüren birboot()metodu ekleyin:Ayrıca şu değeri döndüren birBooting computer... [processor.process() result] [memory.load() result] System ready!getSpecs()metodu ekleyin:Specs: [processor brand] CPU, [memory sizeGB]GB [memory type]Main.java: Oluşturduğunuz sistemi hayata geçirin! Dört girdi alacaksınız: işlemci markası (String), işlemci hızı (double), bellek türü (String) ve bellek boyutu (int).Bu değerlerle bir Processor ve Memory oluşturun, ardından bunları bir Computer içinde birleştirin.
boot()metodunu çağırmanın sonucunu yazdırın, ardındangetSpecs()sonucunu yazdırın.
Sırasıyla dört girdi alacaksınız: işlemci markası, işlemci hızı (GHz), bellek türü ve bellek boyutu (GB).
Computer sınıfının, bileşenlerin kendisi olmaya çalışmak yerine işi onlara nasıl devrettiğine (delegate) dikkat edin—kompozisyonun gücü budur! Computer, ona verdiğiniz herhangi bir Processor veya Memory'yi kullanabilir, bu da tasarımı esnek ve gerçekçi kılar.
Kopya kağıdı
Kompozisyon (Composition), bir sınıfın diğer sınıfları genişletmek yerine onları alan (field) olarak içerdiği bir "has-a" (sahip olma) ilişkisi oluşturur.
Kalıtım (Inheritance) vs Kompozisyon (Composition):
// Kalıtım: Araba bir Motordur (mantıklı değil)
class Car extends Engine { }
// Kompozisyon: Arabanın bir Motoru VARDIR (mantıklı)
class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.ignite();
}
}Kompozisyonun Avantajları:
- Nesneler çalışma zamanında (runtime) değiştirilebilir
- Birden fazla sınıftan gelen davranışlar birleştirilebilir
- Daha iyi kapsülleme (encapsulation) - sadece seçilen metotlar dışarı açılır
- Daha esnek ve bakımı kolay kod
Ne Zaman Kullanılmalı:
- Kalıtım: Gerçek bir "is-a" (bir ...-dır) ilişkisi olduğunda ve alt sınıf, üst sınıfın özelleşmiş bir versiyonu olduğunda kullanın
- Kompozisyon: O türden olmadan başka bir sınıfın işlevselliğine ihtiyaç duyduğunuzda kullanın
En İyi Uygulama: "Kalıtım yerine kompozisyonu tercih edin"
Kendin dene
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Girdileri oku
String processorBrand = scanner.nextLine();
double processorSpeed = Double.parseDouble(scanner.nextLine());
String memoryType = scanner.nextLine();
int memorySize = Integer.parseInt(scanner.nextLine());
// TODO: Marka ve hız ile bir Processor oluşturun
// TODO: Tip ve boyut ile bir Memory oluşturun
// TODO: Processor ve Memory bileşenlerini birleştirerek bir Computer oluşturun
// TODO: boot() sonucunu yazdırın
// TODO: getSpecs() sonucunu yazdırın
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesnelerthis Anahtar KelimesiMetotlarAlanlar (Öznitelikler)Yapıcı MetotYapıcı Metot Aşırı YüklemeÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (extends)super Anahtar KelimesiMetot Geçersiz Kılma (@Override)Yapıcı Metot ZincirlemeObject SınıfıTekli ve Çok Seviyeli KalıtımNeden Çoklu Sınıf Kalıtımı Yok?Özet - Çalışan Hiyerarşisi7Özel Metotlar ve Object Sınıfı
toString() Metoduequals() ve hashCode()clone() MetoducompareTo() ve ComparableComparator ArayüzüÖzet - Özel Sıralama2Erişim Belirleyiciler ve Kapsülleme
Erişim Seviyelerine Genel BakışGetter ve Setter MetotlarıBilgi Gizlemefinal Anahtar KelimesiÖzet - Banka Hesabı Yöneticisi5Polimorfizm
Metot Aşırı Yükleme TemelleriMetot Geçersiz Kılma (Çalışma Zamanı)Upcasting ve Downcastinginstanceof OperatörüSoyut Sınıflar ve MetotlarÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımAgregasyon vs KompozisyonDahili, Yuvalanmış ve Anonim SınıflarEnum'lar ve Enum MetotlarıRecords (Java 16+)Sealed Classes (Java 17+)11Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıBuilder KalıbıObserver KalıbıStrategy Kalıbı14Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi3Sınıf Özellikleri ve Statik Üyeler
Instance ve Statik DeğişkenlerStatik MetotlarStatik BloklarSabitler (static final)Özet - Sayaç ve Utility6Arayüzler ve Soyut Sınıflar
Arayüzlere GirişArayüzleri UygulamaÇoklu Arayüz UygulamaArayüzlerde Default ve StaticSoyut Sınıflar ve ArayüzlerFonksiyonel ArayüzlerÖzet - Ödeme Sistemi9Generics
Generics'e GirişGeneric SınıflarGeneric MetotlarSınırlandırılmış Tip ParametreleriWildcard'lar (?, extends, super)Özet - Generic Container12Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıYineleyici Kalıbı