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 101 / 104.

Composite deseni, tekil nesneleri ve nesne gruplarını tek tipte ele almanıza olanak tanır. Nesneleri, hem tekil öğelerin hem de öğe kapsayıcılarının aynı arayüzü paylaştığı ağaç yapılarında birleştirir. Bu; dosya sistemleri, organizasyon şemaları veya kullanıcı arayüzü bileşenleri gibi hiyerarşileri temsil etmek için idealdir.

Desen üç ana bölümden oluşur: ortak işlemleri tanımlayan bir Component arayüzü, tekil nesneleri temsil eden Leaf sınıfları ve alt öğeleri içeren ve işlemleri onlara devreden Composite sınıfları:

#include <iostream>
#include <memory>
#include <vector>
#include <string>

// Bileşen arayüzü
class FileSystemItem {
public:
    virtual void display(int indent = 0) const = 0;
    virtual int getSize() const = 0;
    virtual ~FileSystemItem() = default;
};

// Yaprak (Leaf) - bireysel dosyaları temsil eder
class File : public FileSystemItem {
    std::string name;
    int size;
public:
    File(const std::string& n, int s) : name(n), size(s) {}
    
    void display(int indent = 0) const override {
        std::cout << std::string(indent, ' ') << name 
                  << " (" << size << " KB)\n";
    }
    int getSize() const override { return size; }
};

// Kompozit (Composite) - diğer bileşenleri içerir
class Folder : public FileSystemItem {
    std::string name;
    std::vector<std::shared_ptr<FileSystemItem>> children;
public:
    Folder(const std::string& n) : name(n) {}
    
    void add(std::shared_ptr<FileSystemItem> item) {
        children.push_back(item);
    }
    
    void display(int indent = 0) const override {
        std::cout << std::string(indent, ' ') << "[" << name << "]\n";
        for (const auto& child : children) {
            child->display(indent + 2);
        }
    }
    
    int getSize() const override {
        int total = 0;
        for (const auto& child : children) {
            total += child->getSize();
        }
        return total;
    }
};

Folder bileşeni alt öğeleri saklar ve bunlar üzerinde döngü kurarak işlemleri gerçekleştirir. Bir klasör üzerinde getSize() metodunu çağırdığınızda, içerdiği tüm öğelerin toplam boyutunu özyinelemeli olarak hesaplar. İstemci kodunun bir dosya mı yoksa bir klasörle mi çalıştığını bilmesine gerek yoktur; her ikisi de aynı arayüze yanıt verir.

Parça-bütün hiyerarşilerini temsil etmeniz gerektiğinde ve istemcilerin tekil nesneleri ve kompozisyonları tek tipte ele almasını istediğinizde Composite kullanın.

challenge icon

Görev

Kolay

Composite desenini kullanarak bir Organizasyon Şeması sistemi oluşturalım. Hem bireysel çalışanların hem de departmanların (diğer çalışanları veya alt departmanları içeren) tek tip olarak ele alınabildiği bir hiyerarşi oluşturacaksınız. Bu, gerçek şirketlerin nasıl yapılandırıldığını yansıtır; departmanlar insanları ve diğer departmanları içererek bir ağaç yapısı oluşturur.

Kodunuzu üç dosya halinde düzenleyeceksiniz:

  • OrgComponent.h: Hem çalışanların hem de departmanların uygulayacağı bileşen arayüzünü tanımlayın.

    Şu özelliklere sahip soyut bir OrgComponent sınıfı oluşturun:

    • getName() — bileşenin adını döndürür
    • getSalary() — toplam maaşı döndürür (çalışanlar için kendi maaşları; departmanlar için içerilen tüm maaşların toplamı)
    • display(int indent = 0) — bileşeni uygun girintiyle görüntüler

    Sanal bir yıkıcı (virtual destructor) ekleyin.

  • Organization.h: Yaprak (leaf) ve bileşik (composite) sınıfları uygulayın.

    Ad ve maaş bilgilerini saklayan bir Employee sınıfı (yaprak) oluşturun. Bu sınıfın display() metodu, çalışan bilgilerini şu formatta yazdırmalıdır:

    [indent spaces]- [name] ($[salary])

    Bir ad ve std::shared_ptr kullanarak OrgComponent çocuklarından oluşan bir koleksiyon saklayan bir Department sınıfı (bileşik) oluşturun. Şunları uygulayın:

    • add(std::shared_ptr<OrgComponent> component) — departmana bir çocuk ekler
    • getSalary() — tüm üyelerin toplam maaşını özyinelemeli (recursive) olarak hesaplar
    • display() — departman adını köşeli parantez içinde yazdırır, ardından tüm çocukları artırılmış girintiyle görüntüler (her seviye için 2 boşluk ekleyin)

    Departmanın görüntüleme formatı şöyle olmalıdır:

    [indent spaces][Department Name]
      [children displayed with indent + 2]
  • main.cpp: Bir organizasyon yapısı oluşturun ve görüntüleyin.

    Dört girdi okuyun:

    1. Şirket adı (string)
    2. Departman adı (string)
    3. Birinci çalışanın adı ve maaşı (format: name,salary)
    4. İkinci çalışanın adı ve maaşı (format: name,salary)

    Bu yapıyı kurun: Bir şirket (üst düzey departman) oluşturun, ona bir alt departman ekleyin ve her iki çalışanı da bu alt departmana ekleyin. Ardından tüm organizasyonu görüntüleyin ve toplam şirket maaşını yazdırın.

    Yapıyı görüntüledikten sonra şunu yazdırın:

    Total Salary: $[amount]

Örneğin, TechCorp, Engineering, Alice,75000 ve Bob,65000 girdileriyle:

[TechCorp]
  [Engineering]
    - Alice ($75000)
    - Bob ($65000)
Total Salary: $140000

StartupInc, Development, Carol,80000 ve Dave,70000 girdileriyle:

[StartupInc]
  [Development]
    - Carol ($80000)
    - Dave ($70000)
Total Salary: $150000

getSalary() metodunun bir çalışan veya bir departman üzerinde çağrılmasından bağımsız olarak nasıl tek tip çalıştığına dikkat edin; departman, tüm üyelerinin maaşlarını otomatik olarak toplar. İstemci kodunun, toplamları hesaplarken veya hiyerarşiyi görüntülerken bireysel çalışanlar ile tüm departmanlar arasında ayrım yapmasına gerek kalmaz.

Kendin dene

#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include "Organization.h"

int main() {
    // Girdileri oku
    std::string companyName;
    std::string departmentName;
    std::string employee1Input;
    std::string employee2Input;
    
    std::getline(std::cin, companyName);
    std::getline(std::cin, departmentName);
    std::getline(std::cin, employee1Input);
    std::getline(std::cin, employee2Input);
    
    // "name,salary" formatını ayrıştırmak için yardımcı lambda
    auto parseEmployee = [](const std::string& input) -> std::pair<std::string, int> {
        size_t commaPos = input.find(',');
        std::string name = input.substr(0, commaPos);
        int salary = std::stoi(input.substr(commaPos + 1));
        return {name, salary};
    };
    
    auto [name1, salary1] = parseEmployee(employee1Input);
    auto [name2, salary2] = parseEmployee(employee2Input);
    
    // TODO: Şirketi üst düzey bir Department olarak oluşturun
    
    // TODO: Bir alt departman oluşturun
    
    // TODO: Ayrıştırılan verileri kullanarak iki Employee nesnesi oluşturun
    
    // TODO: Çalışanları alt departmana ekleyin
    
    // TODO: Alt departmanı şirkete ekleyin
    
    // TODO: Tüm organizasyon yapısını görüntüleyin
    
    // TODO: Toplam maaşı şu formatta yazdırın: Total Salary: $[amount]
    
    return 0;
}
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