Menu
Coddy logo textTech

Kompozit Kalıbı

Coddy'nin C# Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 61 / 70.

Composite deseni, nesneleri ağaç yapıları şeklinde düzenlemenize ve tekil nesneler ile nesne gruplarına tek tipte davranmanıza olanak tanıyan yapısal bir desendir. Hem tekil öğelerle hem de koleksiyonlarla aynı arayüz üzerinden çalışmak istediğiniz parça-bütün hiyerarşilerini temsil etmek için mükemmeldir.

Desen üç ana bileşene sahiptir: ortak işlemleri tanımlayan bir bileşen arayüzü, tekil nesneleri temsil eden yaprak sınıflar ve alt öğeleri içeren ve aynı arayüzü uygulayan bileşik sınıflar:

public interface IFileSystemItem
{
    string Name { get; }
    int GetSize();
}

public class File : IFileSystemItem
{
    public string Name { get; }
    private int _size;
    
    public File(string name, int size)
    {
        Name = name;
        _size = size;
    }
    
    public int GetSize() => _size;
}

public class Folder : IFileSystemItem
{
    public string Name { get; }
    private List<IFileSystemItem> _items = new List<IFileSystemItem>();
    
    public Folder(string name) => Name = name;
    
    public void Add(IFileSystemItem item) => _items.Add(item);
    
    public int GetSize() => _items.Sum(item => item.GetSize());
}

Bu desenin güzelliği, istemcilerin tek bir dosyayla mı yoksa tüm bir klasör hiyerarşisiyle mi çalıştıklarını bilmelerine gerek olmamasıdır:

var root = new Folder("root");
root.Add(new File("doc.txt", 100));

var subFolder = new Folder("images");
subFolder.Add(new File("photo.jpg", 500));
subFolder.Add(new File("icon.png", 50));

root.Add(subFolder);

Console.WriteLine(root.GetSize());  // 650

Composite deseni; dosya sistemleri, UI bileşen ağaçları, organizasyon şemaları veya kapsayıcılar ile içeriklerin aynı şekilde ele alınması gereken her türlü yapı için idealdir. Basit ve karmaşık öğeler arasında ayrım yapma ihtiyacını ortadan kaldırarak istemci kodunu basitleştirir.

challenge icon

Görev

Kolay

Composite desenini kullanarak bir organizasyon şeması sistemi oluşturalım. Hem bireysel çalışanların hem de departmanların (çalışanları veya diğer departmanları içeren) tek tip olarak ele alınabildiği bir yapı oluşturacaksınız; bu yapı, hiyerarşinin herhangi bir seviyesindeki toplam maaş maliyetini hesaplamanıza olanak tanıyacak.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • OrgComponent.cs: Organization ad alanı (namespace) içinde iki üyeye sahip bir IOrgComponent arayüzü tanımlayın: bir Name özelliği (string) ve tam sayı döndüren bir GetSalary() metodu. Bu arayüz, hem bireysel çalışanların hem de departmanların izleyeceği ortak sözleşmeyi temsil eder.
  • OrgClasses.cs: Aynı ad alanı içinde iki sınıf oluşturun:
    • Employee - bireysel bir çalışanı temsil eden bir yaprak (leaf) sınıfı. Yapıcısında (constructor) bir isim ve maaş alır ve kendi maaşını döndürerek arayüzü uygular.
    • Department - bir grubu temsil eden bir bileşik (composite) sınıf. Yapıcısında bir isim alır ve IOrgComponent öğelerinden oluşan bir liste tutar. Üye eklemek için bir Add(IOrgComponent component) metodu ekleyin. GetSalary() metodu, tüm üyelerinin maaşlarının toplamını döndürmelidir.
  • Program.cs: Girdiye dayalı bir organizasyon yapısı oluşturun ve toplam maaşı hesaplayın. Departmanlar ve çalışanlar oluşturacak, bunları uygun şekilde iç içe yerleştirecek ve bileşik desenin tüm hiyerarşiyi nasıl tek tip olarak ele almanızı sağladığını göstereceksiniz.

Aşağıdaki girdileri alacaksınız:

  • Oluşturulacak bileşen sayısı
  • Her bileşen için: tür (employee veya department), ardından isim ve çalışanlar için maaşları. Departmanlar için ayrıca üst departman adını (veya üst düzey bir departmansa root) alacaksınız.

Her bileşen için girdi formatı:

employee
{name}
{salary}
{parent_department}

department
{name}
{parent_department}

Yapıyı oluşturduktan sonra, kök departmanın toplam maaşını {root_name} Total Salary: {amount} formatında yazdırın.

Örneğin, girdiler şunlarsa:

5
department
Engineering
root
employee
Alice
5000
Engineering
employee
Bob
4500
Engineering
department
QA
Engineering
employee
Charlie
4000
QA

Çıktı şöyle olmalıdır:

Engineering Total Salary: 13500

Engineering departmanı Alice (5000), Bob (4500) ve QA departmanını içerir. QA ise Charlie (4000) içerir. Engineering üzerinde GetSalary() çağırdığınızda, tüm iç içe geçmiş bileşenlerden toplamı özyinelemeli olarak hesaplar - bu da Composite deseninin karmaşık ağaç yapılarıyla basit ve tek tip bir arayüz üzerinden çalışmanıza nasıl olanak tanıdığını gösterir!

Kopya kağıdı

Composite deseni, nesneleri ağaç yapıları şeklinde düzenleyen ve tekil nesneler ile grupları aynı arayüz üzerinden tek tip olarak ele alan yapısal bir desendir. Parça-bütün hiyerarşileri için idealdir.

Desenin üç ana bileşeni vardır:

  • Bileşen arayüzü (Component interface): Ortak işlemleri tanımlar
  • Yaprak sınıflar (Leaf classes): Tekil nesneleri temsil eder
  • Kompozit sınıflar (Composite classes): Alt öğeleri içerir ve aynı arayüzü uygular

Temel uygulama örneği:

// Bileşen arayüzü
public interface IFileSystemItem
{
    string Name { get; }
    int GetSize();
}

// Yaprak sınıf
public class File : IFileSystemItem
{
    public string Name { get; }
    private int _size;
    
    public File(string name, int size)
    {
        Name = name;
        _size = size;
    }
    
    public int GetSize() => _size;
}

// Kompozit sınıf
public class Folder : IFileSystemItem
{
    public string Name { get; }
    private List<IFileSystemItem> _items = new List<IFileSystemItem>();
    
    public Folder(string name) => Name = name;
    
    public void Add(IFileSystemItem item) => _items.Add(item);
    
    public int GetSize() => _items.Sum(item => item.GetSize());
}

Kullanım - istemciler tekil öğelerle ve koleksiyonlarla tek tip bir şekilde çalışır:

var root = new Folder("root");
root.Add(new File("doc.txt", 100));

var subFolder = new Folder("images");
subFolder.Add(new File("photo.jpg", 500));
subFolder.Add(new File("icon.png", 50));

root.Add(subFolder);

Console.WriteLine(root.GetSize());  // 650

Composite deseni; dosya sistemleri, kullanıcı arayüzü bileşen ağaçları, organizasyon şemaları veya kapsayıcılar ile içeriklerin aynı şekilde ele alınması gereken her türlü yapı için kullanışlıdır.

Kendin dene

using System;
using System.Collections.Generic;
using Organization;

class Program
{
    public static void Main(string[] args)
    {
        int n = Convert.ToInt32(Console.ReadLine());
        
        // TODO: Departmanları isme göre saklamak için bir sözlük (dictionary) oluşturun
        // Bu, bileşenleri eklerken üst departmanları bulmanıza yardımcı olacaktır
        Dictionary<string, Department> departments = new Dictionary<string, Department>();
        
        // TODO: Kök (root) departmanı takip edin
        Department root = null;
        
        for (int i = 0; i < n; i++)
        {
            string type = Console.ReadLine();
            
            if (type == "department")
            {
                string name = Console.ReadLine();
                string parent = Console.ReadLine();
                
                // TODO: Departmanı oluşturun
                // TODO: Onu departments sözlüğüne ekleyin
                // TODO: Eğer parent "root" ise, bu kök departmandır
                // TODO: Aksi takdirde, üst departmanı bulun ve bu departmanı ona ekleyin
            }
            else if (type == "employee")
            {
                string name = Console.ReadLine();
                int salary = Convert.ToInt32(Console.ReadLine());
                string parent = Console.ReadLine();
                
                // TODO: Çalışanı oluşturun
                // TODO: Üst departmanı bulun ve çalışanı ona ekleyin
            }
        }
        
        // TODO: Kök departmanın toplam maaşını yazdırın
        // Format: "{root_name} Total Salary: {amount}"
        Console.WriteLine($"{root.Name} Total Salary: {root.GetSalary()}");
    }
}
quiz iconKendini test et

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