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.
Görev
KolayComposite 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
OrgComponentsınıfı oluşturun:getName()— bileşenin adını döndürürgetSalary()— 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
Employeesınıfı (yaprak) oluşturun. Bu sınıfındisplay()metodu, çalışan bilgilerini şu formatta yazdırmalıdır:[indent spaces]- [name] ($[salary])Bir ad ve
std::shared_ptrkullanarakOrgComponentçocuklarından oluşan bir koleksiyon saklayan birDepartmentsınıfı (bileşik) oluşturun. Şunları uygulayın:add(std::shared_ptr<OrgComponent> component)— departmana bir çocuk eklergetSalary()— tüm üyelerin toplam maaşını özyinelemeli (recursive) olarak hesaplardisplay()— 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:
- Şirket adı (string)
- Departman adı (string)
- Birinci çalışanın adı ve maaşı (format:
name,salary) - İ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: $140000StartupInc, Development, Carol,80000 ve Dave,70000 girdileriyle:
[StartupInc]
[Development]
- Carol ($80000)
- Dave ($70000)
Total Salary: $150000getSalary() 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.
Kopya kağıdı
Composite deseni, hem tekil öğelerin hem de kapsayıcıların aynı arayüzü paylaştığı ağaç yapıları oluşturarak, tekil nesnelere ve nesne gruplarına tek tip bir şekilde yaklaşır.
Desen üç temel bölümden oluşur:
- Component (Bileşen): Ortak işlemleri tanımlayan bir arayüz
- Leaf (Yaprak): Tekil nesneleri temsil eden sınıflar
- Composite (Bileşik): Alt öğeleri içeren ve işlemleri onlara devreden sınıflar
Bir dosya sisteminin örnek uygulaması:
#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 - tekil 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; }
};
// Bileşik - 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;
}
};Bileşik (composite), alt öğeleri std::shared_ptr kullanarak saklar ve işlemleri bunlar üzerinden yineleyerek gerçekleştirir. getSize() gibi işlemler, tüm hiyerarşi boyunca toplamları hesaplayarak özyinelemeli (recursive) olarak çalışır.
Parça-bütün hiyerarşilerini temsil etmeniz gerektiğinde ve istemcilerin tekil nesnelere ve bileşimlere tek tip davranmasını istediğinizde Composite desenini kullanın.
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;
}
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 DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı11İleri Düzey OOP Kavramları
Kompozisyon ve Kalıtım KarşılaştırmasıCRTP ile Mixin YapılarıPimpl İdiyomuTür Silme (Type Erasure)Enum Sınıfları ve Güçlü TiplendirmeOOP'de İstisna YönetimiÖzel İstisna Hiyerarşileri14Tasarı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ıBir Kalıp Olarak RAII3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic Konteyner