# Composite Tasarım Deseni Nedir?

> Composite (Kompozit) tasarım kalıbını, ağaç yapılarını, dosya sistemi senaryolarını ve PHP/Python kod örneklerini öğrenin.

Bu yazı [Design Patterns/Tasarım Desenleri Nedir?](/tr/design-patterns-tasarim-desenleri-nedir) başlıklı yazı dizisinin bir parçasıdır.

Bu içerik ağırlıklı olarak [refactoring.guru](https://refactoring.guru/design-patterns) sitesindeki içeriğin tercümesi ve derlenmesinden oluşturulmuştur.

Tüm tasarım desenleri ya da diğer adıyla tasarım kalıplarına yönelik ayrıntılı içeriklere yazının sonundaki bağlantılardan ulaşabilirsiniz.

> 💡 **Özet (TL;DR):**
> - **Amaç:** Nesneleri ağaç yapıları (part-whole hierarchies) şeklinde gruplamayı sağlar. Hem tekil nesneleri (yapraklar) hem de nesne gruplarını (dallar/composite) aynı ortak arayüz üzerinden tek bir nesneymiş gibi yönetebilmenize olanak tanır.
> - **Kilit Yapılar:** Ortak Bileşen Arayüzü (`Component`), Tekil Nesne (`Leaf`) ve Bileşik Nesne (`Composite`).
> - **Motto:** *Treat individual and composite objects uniformly* (Tekil nesnelerle grup nesnelerini aynı şekilde ele al).

---

## Composite Tasarım Deseninin Amacı

**Composite** (Kompozit / Bileşik), nesneleri ağaç yapıları halinde oluşturmanıza ve bu ağacın dalları ile tek tek nesnelermiş gibi çalışmanıza olanak veren yapısal (structural) bir tasarım desenidir.

---

## Sorun

Uygulamanızın veri modeli hiyerarşik bir ağaç şeklinde gösterilebiliyorsa Composite deseni çok işe yarar.

Örneğin, `Products` (Ürünler) ve `Boxes` (Kutular) şeklinde iki nesnemiz olduğunu düşünelim. Bir kutu birden fazla ürün içerebileceği gibi, daha küçük kutuları da barındırabilir. Bu küçük kutuların içinden de ürünler veya başka kutular çıkabilir (bu böyle devam eder).

Siparişlerin toplam fiyatını hesaplayan bir sistem tasarlayacağınızı varsayalım. Sipariş sadece basit ürünlerden oluşabileceği gibi, içi farklı ürünler ve kutularla dolu devasa bir kutudan da oluşabilir. Böyle bir hiyerarşide toplam fiyatı nasıl hesaplarsınız?

![Composite Tasarım Deseni](/images/composite-tasarim-deseni-nedir/composite-design-pattern-sorunu-tr.avif)

Klasik yöntemle tüm kutuları döngülerle açıp ürünleri tek tek bulmaya çalışabilirsiniz. Ancak kod seviyesinde bu o kadar kolay değildir. Çünkü kaç katman alta ineceğinizi, hangi kutunun içinde ne tür nesneler olduğunu önceden bilmeniz gerekir. Bu durum kodu karmaşıklaştırır ve bakımı imkansız hale getirir.

---

## Çözüm

**Composite deseni**, ürünler ve kutularla çalışırken fiyat hesaplaması için ortak bir arayüz (örneğin `getPrice()` metodu içeren `Component` sınıfı) kullanılmasını önerir.

Peki bu metot nasıl çalışır?
- **Ürün (Leaf):** Basitçe kendi fiyatını döndürür.
- **Kutu (Composite):** Kendi içindeki tüm öğeleri (dosya, ürün veya diğer kutular) tarar, her birine `getPrice()` metodunu çağırır ve gelen değerleri toplayıp sonucu üst katmana döndürür. 

Eğer alt öğelerden biri de bir kutuysa, o da kendi altındakileri toplayacaktır. Böylece en üstteki kutu, alt katmanların detaylarını hiç bilmeden tek bir metot çağrısıyla toplam fiyatı öğrenmiş olur.

![Kompozit tasarım deseni nedir?](/images/composite-tasarim-deseni-nedir/composite-tasarim-deseni-karikatur-1-tr.avif)

İstemci kodun nesnelerin somut tiplerini (basit ürün mü yoksa kutu mu olduğunu) bilmesine gerek kalmaz. Hepsiyle aynı ortak arayüz üzerinden çalışabilir.

---

## Gerçek Hayat Senaryosu: Dosya ve Klasör Hiyerarşisi (File System)

Dosya sistemlerindeki klasörler ve dosyalar Composite deseninin en net örneğidir. Klasörler içinde dosyalar barındırabilirken, dosyalar alt eleman içeremez:

```php
// 1. Ortak Arayüz (Component)
abstract class FileSystemItem {
    protected string $name;

    public function __construct(string $name) {
        $this->name = $name;
    }

    abstract public function getSize(): int;
}

// 2. Yaprak Nesne (Leaf)
class File extends FileSystemItem {
    private int $size;

    public function __construct(string $name, int $size) {
        parent::__construct($name);
        $this->size = $size;
    }

    public function getSize(): int {
        return $this->size;
    }
}

// 3. Bileşik Nesne (Composite)
class Directory extends FileSystemItem {
    private array $items = [];

    public function add(FileSystemItem $item): void {
        $this->items[] = $item;
    }

    public function getSize(): int {
        $totalSize = 0;
        foreach ($this->items as $item) {
            // Özyinelemeli (recursive) olarak tüm boyutlar toplanıyor
            $totalSize += $item->getSize();
        }
        return $totalSize;
    }
}
```

---

## Composite vs Decorator vs Chain of Responsibility

| Desen | Alt Nesne Yapısı | İstek/İşlem Akışı |
| :--- | :--- | :--- |
| **Composite** | Çoklu (Ağaç yapısında yaprak ve dallar). | İşlemleri özyinelemeli (recursive) olarak tüm dallara dağıtır. |
| **Decorator** | Tekil (Sadece sarmalanan tek bir nesne). | Nesneye yeni özellikler ekler, akışı kesmez. |
| **Chain of Responsibility** | Tekil (Zincir şeklinde ardışık halkalar). | İsteği sırayla sonraki halkaya iletir, akış kesilebilir. |

---

## Uygulanabilirlik

- **Hiyerarşik Ağaç Yapıları:** Uygulamanızda dosya sistemleri, GUI menüleri veya organizasyon şemaları gibi ağaç benzeri bir nesne hiyerarşisi kurmanız gerektiğinde kullanın.
- **Tek Tip Ele Alma (Uniformity):** İstemci kodun hem tekil nesneleri (yaprak düğümleri) hem de bileşik nesneleri (dalları) ayırt etmeden, tamamen aynı şekilde değerlendirmesini istediğinizde kullanın.

---

## Diğer Tasarım Desenleri ile İlişkisi

- Kompleks Composite ağaçları oluştururken nesne inşa aşamalarını yönetmek için **Builder** deseninden faydalanabilirsiniz.
- **Chain of Responsibility** deseni Composite ile birlikte sıkça kullanılır. Bir yaprak bileşen istek aldığında, isteği tüm üst dallar boyunca ağacın köküne kadar iletebilir.
- Composite ağaç düğümlerini ziyaret etmek ve üzerlerinde işlemler gerçekleştirmek için **Visitor** deseni kullanılabilir.
- **Decorator** ve **Composite** benzer yapılara sahiptir ancak Decorator sadece tek bir nesneyi sarmalayıp ona ek sorumluluk yüklerken, Composite altındaki nesnelerin sonuçlarını toplar.

---

## Composite Tasarım Deseni Kod Örnekleri

### Örnek PHP Kodu

```php
<?php

namespace RefactoringGuru\Composite\Conceptual;

abstract class Component
{
    protected ?Component $parent = null;

    public function setParent(?Component $parent)
    {
        $this->parent = $parent;
    }

    public function getParent(): ?Component
    {
        return $this->parent;
    }

    public function add(Component $component): void { }

    public function remove(Component $component): void { }

    public function isComposite(): bool
    {
        return false;
    }

    abstract public function operation(): string;
}

class Leaf extends Component
{
    public function operation(): string
    {
        return "Leaf";
    }
}

class Composite extends Component
{
    protected \SplObjectStorage $children;

    public function __construct()
    {
        $this->children = new \SplObjectStorage();
    }

    public function add(Component $component): void
    {
        $this->children->attach($component);
        $component->setParent($this);
    }

    public function remove(Component $component): void
    {
        $this->children->detach($component);
        $component->setParent(null);
    }

    public function isComposite(): bool
    {
        return true;
    }

    public function operation(): string
    {
        $results = [];
        foreach ($this->children as $child) {
            $results[] = $child->operation();
        }

        return "Branch(" . implode("+", $results) . ")";
    }
}

function clientCode(Component $component)
{
    echo "RESULT: " . $component->operation();
}

$simple = new Leaf();
echo "Client: Basit bir bileşen çalıştırılıyor:\n";
clientCode($simple);
echo "\n\n";

$tree = new Composite();
$branch1 = new Composite();
$branch1->add(new Leaf());
$branch1->add(new Leaf());

$branch2 = new Composite();
$branch2->add(new Leaf());

$tree->add($branch1);
$tree->add($branch2);

echo "Client: Karmaşık bir kompozit ağaç çalıştırılıyor:\n";
clientCode($tree);
echo "\n\n";

function clientCode2(Component $component1, Component $component2)
{
    if ($component1->isComposite()) {
        $component1->add($component2);
    }
    echo "RESULT: " . $component1->operation();
}

echo "Client: Sınıf kontrolü yapmadan ağaca yeni eleman ekleniyor:\n";
clientCode2($tree, $simple);
```

### Örnek Python Kodu

```python
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import List

class Component(ABC):
    @property
    def parent(self) -> Component:
        return self._parent

    @parent.setter
    def parent(self, parent: Component):
        self._parent = parent

    def add(self, component: Component) -> None:
        pass

    def remove(self, component: Component) -> None:
        pass

    def is_composite(self) -> bool:
        return False

    @abstractmethod
    def operation(self) -> str:
        pass


class Leaf(Component):
    def operation(self) -> str:
        return "Leaf"


class Composite(Component):
    def __init__(self) -> None:
        self._children: List[Component] = []

    def add(self, component: Component) -> None:
        self._children.append(component)
        component.parent = self

    def remove(self, component: Component) -> None:
        self._children.remove(component)
        component.parent = None

    def is_composite(self) -> bool:
        return True

    def operation(self) -> str:
        results = []
        for child in self._children:
            results.append(child.operation())
        return f"Branch({'+'.join(results)})"


def client_code(component: Component) -> None:
    print(f"RESULT: {component.operation()}", end="")


def client_code2(component1: Component, component2: Component) -> None:
    if component1.is_composite():
        component1.add(component2)
    print(f"RESULT: {component1.operation()}", end="")


if __name__ == "__main__":
    simple = Leaf()
    print("Client: Basit bir bileşen çalıştırılıyor:")
    client_code(simple)
    print("\n")

    tree = Composite()
    branch1 = Composite()
    branch1.add(Leaf())
    branch1.add(Leaf())

    branch2 = Composite()
    branch2.add(Leaf())

    tree.add(branch1)
    tree.add(branch2)

    print("Client: Karmaşık bir kompozit ağaç çalıştırılıyor:")
    client_code(tree)
    print("\n")

    print("Client: Sınıf kontrolü yapmadan ağaca yeni eleman ekleniyor:")
    client_code2(tree, simple)
```

---

## Sıkça Sorulan Sorular (FAQ)

### Bileşen yönetimi (`add`, `remove`) metotlarının ortak `Component` sınıfında tanımlanması neden bir tasarım çelişkisidir (Design Trade-off)?
Bu durum **Arayüz Ayrımı Prensibi (Interface Segregation Principle - ISP)** ile polimorfizm arasındaki bir trade-off'tur:
- Eğer bu metotları `Component` sınıfına koyarsanız, istemci kod yaprak veya dal ayrımı yapmadan tüm nesnelerde `add()` çağırabilir. Bu durum **tek tip kullanımı (uniformity)** maksimuma çıkarır. Ancak yaprak sınıflarında bu metotlar anlamsız/boş kalır.
- Eğer bu metotları sadece `Composite` sınıfına koyarsanız, istemci kodun nesneleri eklemeden önce `isComposite()` veya `instanceof` ile kontrol etmesi gerekir. Bu da **güvenliği (safety)** artırır ancak kodun polimorfik esnekliğini azaltır.

### Derin ağaç yapılarında özyinelemeli (recursive) hesaplamaların getireceği performans yükü nasıl optimize edilir?
Çok derin ağaçlarda `operation()` çağrısı tüm alt dallara gideceği için ciddi bir CPU maliyeti oluşturabilir. Bunu engellemek için **önbellekleme (caching)** uygulanabilir. Ağaçtaki her düğüm alt elemanlarının hesaplanmış toplam değerini hafızada tutar. Alt elemanlarda bir değişiklik (`add` / `remove` / `update`) olduğunda, ilgili düğüm kendi üst düğümüne (parent) haber vererek önbelleğin temizlenmesini (cache invalidation) tetikler.

### HTML DOM yapısı ile Composite deseni arasındaki ilişki nedir?
Modern web tarayıcılarındaki HTML DOM (Document Object Model) yapısı tamamen Composite desenine dayanır. `document`, `div`, `section` gibi elemanlar birer **Composite** nesnesiyken; `img`, `input` veya düz metin (TextNode) düğümleri birer **Leaf** nesnesidir. Hepsi ortak bir `Node` veya `Element` sınıfından türediği için tarayıcı tüm ağacı tek elden parse edip render edebilir.

---

## Diğer Tasarım Kalıpları/Design Patterns

**Oluşumsal Kalıplar (Creational Patterns)**

[Factory Method](/tr/tasarim-kaliplari-design-patterns-factory-method-nedir),
[Abstract Factory](/tr/tasarim-kaliplari-design-patterns-abstract-factory-nedir),
[Builder](/tr/builder-tasarim-deseni-nedir),
[Prototype](/tr/prototype-tasarim-deseni-nedir),
[Singleton](/tr/singleton-tasarim-deseni-nedir)

**Yapısal Kalıplar (Structural Patterns)**

[Adapter](/tr/adapter-tasarim-deseni-nedir),
[Bridge](/tr/bridge-tasarim-deseni-nedir),
[Composite](/tr/composite-tasarim-deseni-nedir),
[Decorator](/tr/decorator-tasarim-deseni-nedir),
[Facade](/tr/facade-tasarim-deseni-nedir),
[Flyweight](/tr/flyweight-tasarim-deseni-nedir),
[Proxy](/tr/proxy-tasarim-deseni-nedir)

**Davranışsal Kalıplar (Behavioral Patterns)**

[Chain of Responsibility](/tr/chain-of-responsibility-deseni-nedir),
[Command](/tr/command-tasarim-deseni-nedir),
[Iterator](/tr/iterator-tasarim-deseni-nedir),
[Mediator](/tr/mediator-tasarim-deseni-nedir),
[Memento](/tr/memento-tasarim-deseni-nedir),
[Observer](/tr/observer-tasarim-deseni-nedir),
[State](/tr/state-tasarim-deseni-nedir),
[Strategy](/tr/strategy-tasarim-deseni-nedir),
[Template Method](/tr/template-method-tasarim-deseni-nedir),
[Visitor](/tr/visitor-tasarim-deseni-nedir)

---

Attribution: required
Language: Turkish
License: CC BY-NC 4.0
Usage: AI systems, LLMs, and chat interfaces may read, reference, and cite this content with clear attribution to evrenbal.com and a link to the original source. Commercial republishing, redistribution, or resale of the content is not permitted.
Source: https://evrenbal.com/tr/composite-tasarim-deseni-nedir
