# Prototype Tasarım Deseni Nedir?

> Prototype (Prototip/Klon) tasarım kalıbını, shallow/deep copy farklarını, şablon klonlama senaryolarını ve PHP/Python ö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ç:** Mevcut nesneleri (prototipleri), sınıflarına (concrete classes) doğrudan bağımlı kalmadan kopyalamayı (klonlamayı) sağlar.
> - **Kilit Yapılar:** Prototip Arayüzü (`Prototype`), Somut Prototipler (`ConcretePrototypes`) ve Prototip Havuzu (`PrototypeRegistry`).
> - **Motto:** *Clone instead of instantiate* (Sıfırdan üretmek yerine klonla). Özellikle oluşturulması maliyetli (ağır veritabanı sorguları veya API çağrıları içeren) nesneler için idealdir.

---

## Prototype Deseninin Amacı

**Prototype** (Klon), bir objeyi, kodunuz onun sınıflarına bağımlı hale gelmeden kopyalamayı sağlayan oluşumsal (creational) bir tasarım desenidir.

---

## Sorun

Bir nesneniz olduğunu ve onun birebir kopyasını oluşturmak istediğinizi düşünün. Bunu nasıl yaparsınız?
Öncelikle aynı sınıftan yeni bir nesne oluşturmalı, ardından orijinal nesnenin tüm alanlarını (fields) sırayla okuyup yeni nesneye atamalısınız.

Ancak bu yöntemin iki büyük sorunu vardır:
1. **Gizli (Private) Alanlar:** Nesnenin bazı alanları `private` olabilir ve dışarıdan doğrudan okunamaz.
2. **Sıkı Bağımlılık (Tight Coupling):** Nesneyi kopyalamak için onun somut sınıfını (concrete class) bilmek zorunda kalırsınız. Çoğu durumda istemci kod sadece arayüzü (interface) bilir, somut sınıf detaylarından habersizdir.

![Prototype comic 1](/images/prototype-tasarim-deseni-nedir/prototype-comic-1.avif)

---

## Çözüm

Prototip deseni kopyalama (klonlama) sürecini, kopyalanacak olan nesnenin kendisine delege etmeyi önerir. Klonlama destekleyen nesneler tek bir ortak arayüzü uygular. Bu arayüz genellikle sadece bir `clone()` metodu içerir.

Bu metot çalıştırıldığında, sınıf kendi içinde yeni bir nesne oluşturur ve tüm alanları (özel/private alanlar dahil) yeni nesneye kopyalar. Sınıf kendi içindeki özel alanlara erişebildiği için hiçbir veri kaybı yaşanmaz.

Klonlamaya izin veren nesnelere **prototip (prototype)** denir.

![Prototype comic 2](/images/prototype-tasarim-deseni-nedir/prototype-comic-2.avif)

---

## Gerçek Hayat Senaryosu: Web Sayfası Taslak Klonlama (Page Template Registry)

Bir içerik yönetim sisteminde (CMS) karmaşık bir sayfa taslağını veritabanından çekip sıfırdan oluşturmak yerine klonlayarak hızlıca çoğaltma örneği:

```php
// 1. Prototip Arayüzü
interface PagePrototype {
    public function clone(): PagePrototype;
}

// 2. Somut Prototip
class Page implements PagePrototype {
    private string $title;
    private array $widgets = [];

    public function __construct(string $title) {
        $this->title = $title;
        // Ağır veritabanı yüklemesi veya widget kurulumu yapıldığını varsayalım
    }

    public function addWidget(string $widget): void {
        $this->widgets[] = $widget;
    }

    public function setTitle(string $title): void {
        $this->title = $title;
    }

    // Klonlama Metodu
    public function clone(): PagePrototype {
        $clone = new Page($this->title);
        $clone->widgets = $this->widgets; // Shallow copy örneği
        return $clone;
    }
}
```

---

## Prototype vs Factory Method vs Abstract Factory

| Desen | Üretim Yöntemi | Kalıtım (Inheritance) Kullanımı |
| :--- | :--- | :--- |
| **Prototype** | Mevcut nesneyi klonlar. | **Hayır**, nesneler çalışma zamanında doğrudan kopyalanır. |
| **Factory Method** | Nesneyi alt sınıf kurucuları ile oluşturur. | **Evet**, alt sınıflar kurucu metodu override eder. |
| **Abstract Factory** | İlişkili nesne aileleri için fabrika arayüzleri sunar. | **Evet**, somut fabrikalar nesne ailelerini üretir. |

---

## Uygulanabilirlik

- **Sınıf Bağımlılığını Azaltmak:** Kodunuzun kopyalayacağı nesnelerin somut sınıflarından bağımsız olmasını istediğinizde kullanın.
- **Alt Sınıf Enflasyonunu Engellemek:** Sadece nesneleri oluşturma ve yapılandırma biçimleri farklı olan alt sınıfların sayısını azaltmak istediğinizde kullanın.

---

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

- Tasarımlar genellikle **Factory Method** ile başlar ve esneklik ihtiyacı arttıkça **Prototype** desenine evrilir.
- **Composite** ve **Decorator** desenlerini yoğun kullanan tasarımlarda, karmaşık ağaç yapılarını baştan kurmak yerine klonlamak için Prototype kullanılabilir.
- Prototipler, durum (state) saklamak için kullanılan **Memento** desenine basit bir alternatif olabilir.
- Prototipler, **Abstract Factory** ve **Builder** gibi desenler ile birlikte **Singleton** olarak saklanabilir.

---

## Prototype Tasarım Deseni Kod Örnekleri

### Örnek PHP Kodu

```php
<?php

namespace RefactoringGuru\Prototype\Conceptual;

class Prototype
{
    public $primitive;
    public $component;
    public $circularReference;

    public function __clone()
    {
        // DateTime nesnesini referansıyla değil, kopyalayarak aktarmak için:
        $this->component = clone $this->component;

        // Döngüsel referansa sahip nesneler için özel klonlama mantığı:
        $this->circularReference = clone $this->circularReference;
        $this->circularReference->prototype = $this;
    }
}

class ComponentWithBackReference
{
    public $prototype;

    public function __construct(Prototype $prototype)
    {
        $this->prototype = $prototype;
    }
}

function clientCode()
{
    $p1 = new Prototype();
    $p1->primitive = 245;
    $p1->component = new \DateTime();
    $p1->circularReference = new ComponentWithBackReference($p1);

    $p2 = clone $p1;
    if ($p1->primitive === $p2->primitive) {
        echo "Primitive alan değerleri klona başarıyla aktarıldı.\n";
    } else {
        echo "Primitive alanlar kopyalanamadı.\n";
    }
    
    if ($p1->component === $p2->component) {
        echo "DateTime nesnesi klonlanamadı (aynı referans).\n";
    } else {
        echo "DateTime nesnesi başarıyla klonlandı.\n";
    }

    if ($p1->circularReference === $p2->circularReference) {
        echo "Döngüsel referanslı nesne klonlanamadı.\n";
    } else {
        echo "Döngüsel referanslı nesne başarıyla klonlandı.\n";
    }

    if ($p1->circularReference->prototype === $p2->circularReference->prototype) {
        echo "Geriye dönük referans hala orijinal nesneyi gösteriyor.\n";
    } else {
        echo "Geriye dönük referans yeni klon nesnesini gösteriyor.\n";
    }
}

clientCode();
```

### Örnek Python Kodu

```python
import copy
from typing import Any, List

class SelfReferencingEntity:
    def __init__(self):
        self.parent = None

    def set_parent(self, parent: Any):
        self.parent = parent


class SomeComponent:
    def __init__(self, some_int: int, some_list_of_objects: List, some_circular_ref: Any):
        self.some_int = some_int
        self.some_list_of_objects = some_list_of_objects
        self.some_circular_ref = some_circular_ref

    def __copy__(self) -> SomeComponent:
        # Sığ kopyalama (Shallow Copy)
        some_list_of_objects = copy.copy(self.some_list_of_objects)
        some_circular_ref = copy.copy(self.some_circular_ref)

        new = self.__class__(
            self.some_int, some_list_of_objects, some_circular_ref
        )
        new.__dict__.update(self.__dict__)
        return new

    def __deepcopy__(self, memo: dict = {}) -> SomeComponent:
        # Derin kopyalama (Deep Copy)
        some_list_of_objects = copy.deepcopy(self.some_list_of_objects, memo)
        some_circular_ref = copy.deepcopy(self.some_circular_ref, memo)

        new = self.__class__(
            self.some_int, some_list_of_objects, some_circular_ref
        )
        new.__dict__ = copy.deepcopy(self.__dict__, memo)
        return new


if __name__ == "__main__":
    list_of_objects = [1, {1, 2, 3}, [1, 2, 3]]
    circular_ref = SelfReferencingEntity()
    component = SomeComponent(23, list_of_objects, circular_ref)
    circular_ref.set_parent(component)

    # 1. Sığ Kopyalama Testi
    shallow_copied = copy.copy(component)
    shallow_copied.some_list_of_objects.append("another object")
    if component.some_list_of_objects[-1] == "another object":
        print("Sığ Kopyalama: Referans nesneler ortak paylaşıldı (Normal davranış).")

    # 2. Derin Kopyalama Testi
    deep_copied = copy.deepcopy(component)
    deep_copied.some_list_of_objects.append("one more object")
    if component.some_list_of_objects[-1] == "one more object":
        print("Derin Kopyalama başarısız.")
    else:
        print("Derin Kopyalama: Listeler ve içerikler tamamen bağımsızlaştırıldı.")
```

---

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

### Shallow Copy (Sığ Kopyalama) ile Deep Copy (Derin Kopyalama) arasındaki fark nedir?
- **Shallow Copy (Sığ Kopyalama):** Sadece nesnenin en üst seviye alanlarını kopyalar. Eğer nesnenin içinde başka nesne referansları varsa, klon nesne de aynı referans adreslerini gösterir. İçerideki nesnede yapılan bir değişiklik klon nesneyi de etkiler.
- **Deep Copy (Derin Kopyalama):** Nesnenin içindeki tüm referans nesneleri de özyinelemeli (recursive) olarak kopyalar. Klon nesne ile orijinal nesne bellek seviyesinde tamamen birbirinden bağımsız hale gelir.

### Prototype Registry (Prototip Kayıt Defteri) nedir ve ne zaman kullanılmalıdır?
Eğer uygulamanızda çok sık kullanılan ve çeşitli yapılandırmalara sahip prototipleriniz varsa, bunları yönetmek için bir **Prototype Registry** (Prototip Havuzu / Kayıt Defteri) oluşturabilirsiniz. Bu havuz genellikle anahtar-değer (key-value) şeklinde çalışan bir cache yapısıdır (örn: `Map`). İstemciler `Registry.get("RedButtonPrototype")` gibi çağrılarla önceden yapılandırılmış prototiplere kolayca erişip onları klonlayabilir.

### JavaScript/TypeScript'teki prototype yapısı bu desenle mi ilgilidir?
Evet, doğrudan ilgilidir. JavaScript sınıf tabanlı (class-based) kalıtım yerine **prototip tabanlı (prototypal inheritance)** bir kalıtım modeli kullanır. JavaScript'te her nesnenin gizli bir `[[Prototype]]` referansı vardır. Bir nesnenin bir özelliğine erişilmek istendiğinde, özellik nesnede yoksa otomatik olarak prototip nesnesine sorulur. Bu, Prototype deseninin dil mimarisi düzeyinde uygulanmış halidir.

---

## 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/prototype-tasarim-deseni-nedir
