Kompozit Kalıbı
Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 75 / 87.
Composite Deseni (Composite Pattern), nesneleri parça-bütün hiyerarşilerini temsil edecek şekilde ağaç yapılarında birleştirmenize olanak tanıyan yapısal bir tasarım desenidir. İstemcilerin, tekil nesneleri ve nesne topluluklarını ortak bir arayüz üzerinden tek tip olarak ele almalarına olanak tanır.
Bir dosya sistemini düşünün: bir klasör, dosyalar ve daha fazla dosya ve klasör içerebilen diğer klasörleri içerebilir. İster tek bir dosyayla ister tüm bir klasör yapısıyla uğraşıyor olun, "get size" gibi işlemleri aynı şekilde gerçekleştirmek istersiniz. Desen bir Component arayüzü, Leaf nesneleri (tekil öğeler) ve Composite nesneleri (alt öğeleri tutan kapsayıcılar) tanımlar:
interface FileComponent {
void display(String indent);
int getSize();
}
class File implements FileComponent {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public void display(String indent) {
System.out.println(indent + name + " (" + size + "KB)");
}
public int getSize() {
return size;
}
}
class Folder implements FileComponent {
private String name;
private List<FileComponent> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileComponent component) {
children.add(component);
}
public void display(String indent) {
System.out.println(indent + name + "/");
for (FileComponent child : children) {
child.display(indent + " ");
}
}
public int getSize() {
return children.stream().mapToInt(FileComponent::getSize).sum();
}
}Kompozit, işlemleri alt öğelerine devrederek özyinelemeli yapılara olanak tanır. İstemciler, bir yaprakla mı yoksa bir kompozitle mi çalıştıklarını bilmeden ağaçla etkileşime girerler:
Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));
Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);
root.display("");
System.out.println("Total: " + root.getSize() + "KB");Composite Deseni; organizasyon şemaları, UI bileşenleri veya menü sistemleri gibi, gruplara ve bireylere aynı şekilde davranmanız gereken hiyerarşileri temsil etmek için idealdir.
Görev
KolayComposite Pattern kullanarak bir organizasyon şeması sistemi oluşturalım! Departmanların çalışanları ve diğer alt departmanları içerebileceği bir yapı oluşturacaksınız; bu yapı, ister tek bir çalışana ister tüm bir bölüme bakıyor olun, toplam maaşları hesaplamanıza ve hiyerarşiyi tek tip bir şekilde görüntülemenize olanak tanır.
Kodunuzu dört dosya halinde düzenleyeceksiniz:
OrganizationComponent.java: Hem çalışanların hem de departmanların uygulayacağı bileşen arayüzünü (interface) tanımlayın. İki yöntem bildirmelidir: bileşeni uygun girintiyle görüntülemek içinshowDetails(String indent)ve toplam maaşı tam sayı olarak döndürengetSalary().Employee.java: Bireysel çalışanları temsil eden yaprak (leaf) sınıfını oluşturun. BirEmployee, her ikisi de yapıcı (constructor) aracılığıyla ayarlanan bir isme (String) ve maaşa (int) sahiptir.showDetailsçağrıldığında,[indent][name]: $[salary]formatında çıktı vermelidir.getSalaryyöntemi sadece çalışanın maaşını döndürür.Department.java: Hem çalışanları hem de alt departmanları tutabilen bileşik (composite) sınıfı oluşturun. BirDepartmentbir isme (String) sahiptir veOrganizationComponentçocuklarının bir listesini tutar. Üye eklemek için biradd(OrganizationComponent component)yöntemine sahip olmalıdır.showDetailsçağrıldığında,[indent][name] Departmentyazdırır, ardından her bir çocuk üzerinde artırılmış girintiyle (iki boşluk ekleyin)showDetailsyöntemini çağırır.getSalaryyöntemi, tüm çocukların maaşlarının toplamını döndürür.Main.java: Organizasyonunuzu kurun! Dört girdi alacaksınız: maaşlarıyla birlikte iki çalışan ismi ve bir çalışan içeren bir alt departman ismi.Kök dizininiz olarak bir "Engineering" departmanı oluşturun. İlk iki isim/maaş çiftini kullanarak buna iki çalışan ekleyin. Ardından üçüncü girdiyi kullanarak bir alt departman oluşturun, dördüncü isim/maaş çiftini kullanarak buna bir çalışan ekleyin ve bu alt departmanı Engineering departmanına ekleyin.
Engineering departmanı üzerinde
showDetails("")yöntemini çağırın, ardından toplam maaşıTotal Salary: $[amount]formatında yazdırın.
Girdileri şu sırayla alacaksınız: employee1 name (String), employee1 salary (int), employee2 name (String), employee2 salary (int), sub-department name (String), employee3 name (String), employee3 salary (int).
Örneğin, Alice, 75000, Bob, 65000, QA, Charlie, 55000 girdileriyle çıktınız şöyle olacaktır:
Engineering Department
Alice: $75000
Bob: $65000
QA Department
Charlie: $55000
Total Salary: $195000Aynı showDetails ve getSalary yöntemlerinin, ister tek bir çalışan üzerinde ister iç içe geçmiş alt departmanlar içeren koca bir departman üzerinde çağrılsın, nasıl sorunsuz çalıştığına dikkat edin. Bileşik yapı, özyinelemeyi (recursion) otomatik olarak yöneterek tüm hiyerarşiye tek tip bir şekilde davranmanıza olanak tanır!
Kopya kağıdı
Composite Pattern (Bileşik Tasarım Deseni), nesneleri parça-bütün hiyerarşilerini temsil etmek için ağaç yapılarında birleştiren yapısal bir tasarım desenidir. Tekil nesnelerin ve bileşimlerin ortak bir arayüz üzerinden tek tip olarak ele alınmasını sağlar.
Desen üç temel öğeden oluşur:
- Component (Bileşen): Ortak işlemleri tanımlayan arayüz
- Leaf (Yaprak): Bileşen arayüzünü uygulayan tekil nesneler
- Composite (Bileşik): Çocukları tutan ve işlemleri onlara devreden kapsayıcı nesneler
Bir dosya sisteminin örnek uygulaması:
// Bileşen arayüzü
interface FileComponent {
void display(String indent);
int getSize();
}
// Yaprak sınıfı
class File implements FileComponent {
private String name;
private int size;
public File(String name, int size) {
this.name = name;
this.size = size;
}
public void display(String indent) {
System.out.println(indent + name + " (" + size + "KB)");
}
public int getSize() {
return size;
}
}
// Bileşik sınıfı
class Folder implements FileComponent {
private String name;
private List<FileComponent> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileComponent component) {
children.add(component);
}
public void display(String indent) {
System.out.println(indent + name + "/");
for (FileComponent child : children) {
child.display(indent + " ");
}
}
public int getSize() {
return children.stream().mapToInt(FileComponent::getSize).sum();
}
}Bileşik yapının kullanımı:
Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));
Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);
root.display("");
System.out.println("Total: " + root.getSize() + "KB");Bileşik yapı, işlemleri özyinelemeli (recursive) olarak çocuklarına devreder. İstemciler, bir yaprakla mı yoksa bir bileşikle mi çalıştıklarını bilmeden ağaçla etkileşime girerler.
Kullanım durumları: Organizasyon şemaları, kullanıcı arayüzü bileşenleri, menü sistemleri, dosya sistemleri — grupların ve bireylerin aynı muameleyi görmesi gereken her türlü hiyerarşi.
Kendin dene
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Girdileri oku
String emp1Name = scanner.nextLine();
int emp1Salary = Integer.parseInt(scanner.nextLine());
String emp2Name = scanner.nextLine();
int emp2Salary = Integer.parseInt(scanner.nextLine());
String subDeptName = scanner.nextLine();
String emp3Name = scanner.nextLine();
int emp3Salary = Integer.parseInt(scanner.nextLine());
// TODO: Kök olarak "Engineering" departmanını oluşturun
// TODO: emp1 ve emp2 verilerini kullanarak Engineering departmanına iki çalışan oluşturun ve ekleyin
// TODO: subDeptName kullanarak bir alt departman oluşturun
// TODO: emp3 verilerini kullanarak alt departmana bir çalışan oluşturun ve ekleyin
// TODO: Alt departmanı Engineering departmanına ekleyin
// TODO: Engineering departmanı üzerinde showDetails("") metodunu çağırın
// TODO: Toplam maaşı şu formatta yazdırın: Total Salary: $[amount]
}
}
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ı