# Proxy Tasarım Deseni Nedir?

> Proxy (Vekil) tasarım kalıbını, erişim kontrolünü, gecikmeli yüklemeyi (lazy loading), caching 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ç:** Başka bir nesne için yer tutucu veya vekil sağlayarak o nesneye erişimi kontrol etmeyi sağlar. İstek gerçek nesneye ulaşmadan önce veya sonra ek işlemler (yetkilendirme, önbellekleme, loglama vb.) yapılabilmesine izin verir.
> - **Kilit Yapılar:** Ortak Arayüz (`Subject`), Gerçek Nesne (`RealSubject`) ve Vekil Nesnesi (`Proxy`).
> - **Motto:** *Control and Cache* (Erişimi denetle ve önbelleğe al).

---

## Proxy Tasarım Deseninin Amacı

**Proxy** (Vekil / Temsilci), başka bir nesne için bir yedek veya yer tutucu sağlamanıza olanak tanıyan yapısal (structural) bir tasarım desenidir. Bir proxy, orijinal nesneye erişimi kontrol ederek, istek orijinal nesneye ulaşmadan önce veya sonra ek işlemler gerçekleştirmenize izin verir.

---

## Sorun

Çok büyük miktarda sistem kaynağı tüketen devasa bir nesneniz olduğunu düşünün. Bu nesneye her zaman değil, sadece belirli zamanlarda ihtiyaç duyuyorsunuz.

![Proxy tasarım deseni nedir?](/images/proxy-tasarim-deseni-nedir/proxy-tasarim-deseni-nedir.avif)

Veritabanı veya API sorgularını doğrudan tetiklemek yavaş ve maliyetli olabilir. Nesneyi uygulama açıldığında değil, sadece ihtiyaç duyulduğunda oluşturmak için Tembel Başlatma (Lazy Initialization) yöntemi uygulanabilir. 

Ancak bu kodu doğrudan nesneyi kullanan tüm istemcilere yazmak ciddi kod tekrarına neden olur. Kodunu değiştiremediğimiz üçüncü parti kapalı bir kütüphane söz konusu olduğunda ise bu yaklaşım tamamen imkansızlaşır.

---

## Çözüm

**Proxy deseni**, orijinal servis nesnesiyle birebir aynı arayüze (interface) sahip yeni bir ara sınıf (Proxy sınıfı) oluşturmanızı önerir. İstemciler doğrudan gerçek nesneye değil, bu proxy nesnesine istek gönderir. Proxy nesnesi isteği aldığında, gerçek servis nesnesini arka planda başlatır ve işi ona devreder.

![Proxy tasarım deseni nasıl kullanılır?](/images/proxy-tasarim-deseni-nedir/neden-proxy-tasarim-deseni.avif)

Proxy, istemcinin veya gerçek veritabanı nesnesinin haberi olmadan tembel başlatmayı (lazy initialization) yürütür ve gelen sonuçları önbelleğe alır. 

Orijinal sınıfla aynı arayüze sahip olduğu için, istemciler gerçek servis nesnesi yerine proxy nesnesiyle çalıştıklarını fark etmezler bile. Bu sayede ana iş mantığı koduna dokunmadan araya ek yetenekler entegre edilmiş olur.

---

## Gerçek Hayat Senaryosu: YouTube API İsteklerini Önbelleğe Alma (Caching Proxy)

API isteklerinin maliyetini azaltmak ve hızı artırmak amacıyla Caching Proxy şu şekilde kurgulanabilir:

```php
// 1. Ortak Arayüz (Subject)
interface YouTubeServiceInterface {
    public function downloadVideo(string $id): string;
}

// 2. Gerçek Servis (RealSubject)
class ThirdPartyYouTubeClass implements YouTubeServiceInterface {
    public function downloadVideo(string $id): string {
        // Gerçek API'den veri indirme simülasyonu (yavaş işlem)
        sleep(2);
        return "Video verisi ($id)";
    }
}

// 3. Vekil Sınıf (Proxy)
class CachedYouTubeProxy implements YouTubeServiceInterface {
    private ThirdPartyYouTubeClass $service;
    private array $cache = [];

    public function __construct(ThirdPartyYouTubeClass $service) {
        $this->service = $service;
    }

    public function downloadVideo(string $id): string {
        // Önbellek kontrolü yapılıyor
        if (!isset($this->cache[$id])) {
            echo "Önbellekte bulunamadı. API'ye gidiliyor...\n";
            $this->cache[$id] = $this->service->downloadVideo($id);
        } else {
            echo "Video önbellekten getirildi!\n";
        }
        return $this->cache[$id];
    }
}
```

---

## Proxy vs Decorator vs Adapter vs Facade

| Desen | Amaç | Arayüz Etkisi | Yaşam Döngüsü |
| :--- | :--- | :--- | :--- |
| **Proxy** | Erişim kontrolü, caching, tembel yükleme. | Arayüzü **aynı tutar**. | Gerçek nesnenin yaşam döngüsünü **kendisi yönetir**. |
| **Decorator** | Dinamik olarak nesneye yeni yetenekler eklemek. | Arayüzü değiştirmeden **genişletir**. | Sarmalanan nesne dışarıdan **istemci tarafından verilir**. |
| **Adapter** | Uyumsuz sistemleri birleştirmek. | Arayüzü **değiştirir**. | Genelde sadece tek nesneyi sarar. |
| **Facade** | Karmaşık bir alt sistemi basitleştirmek. | **Yeni ve sade bir arayüz** sunar. | Alt sistemdeki birçok nesneyi yönetir. |

---

## Uygulanabilirlik

Proxy deseninin en popüler kullanım alanları şunlardır:

- **Sanal Proxy (Virtual Proxy):** Yoğun sistem kaynağı tüketen ağır bir nesnenin oluşturulmasını gerçekten kullanılacağı ana kadar ötelemek (Lazy Initialization) istediğinizde kullanın.
- **Koruma Proxy'si (Protection Proxy):** Nesnelere yetkilendirme katmanı eklemek ve sadece belirli haklara sahip istemcilerin servis nesnesini çağırmasına izin vermek istediğinizde kullanın.
- **Uzak Proxy (Remote Proxy):** Gerçek nesne başka bir sunucuda veya ağın ucunda olduğunda, ağ bağlantı detaylarını gizleyen yerel bir temsilci sağlamak için kullanın.
- **Önbellek Proxy'si (Caching Proxy):** Pahalı veritabanı veya API sorgularının sonuçlarını önbelleğe alıp istemciye hızlı dönmek istediğinizde kullanın.
- **Loglama Proxy'si (Logging Proxy):** Gerçek nesneye yapılan istekleri loglamak istediğinizde kullanın.

---

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

- **Adapter** nesnenin arayüzünü değiştirirken, **Decorator** nesneyi arayüzünü değiştirmeden genişletir. **Proxy** ise nesneye aynı arayüzle erişim kontrolü sağlar.
- **Facade**, karmaşık bir sistemi basitleştiren bir ara tampon olması yönüyle Proxy'ye benzer. Ancak Proxy, servis nesnesiyle birebir aynı arayüze sahip olduğu için onun yerine doğrudan geçebilir.
- **Decorator** ve **Proxy** benzer yapıdadır ancak Proxy genellikle sarmaladığı nesnenin yaşam süresini kendisi kontrol ederken, Decorator'da bu kontrol her zaman istemcidedir.

---

## Proxy Tasarım Deseni Kod Örnekleri

### Örnek PHP Kodu

```php
<?php

namespace RefactoringGuru\Proxy\Conceptual;

interface Subject
{
    public function request(): void;
}

class RealSubject implements Subject
{
    public function request(): void
    {
        echo "RealSubject: İstek işleniyor.\n";
    }
}

class Proxy implements Subject
{
    private RealSubject $realSubject;

    public function __construct(RealSubject $realSubject)
    {
        $this->realSubject = $realSubject;
    }

    public function request(): void
    {
        if ($this->checkAccess()) {
            $this->realSubject->request();
            $this->logAccess();
        }
    }

    private function checkAccess(): bool
    {
        echo "Proxy: İstek gönderilmeden önce yetkilendirme kontrolü yapılıyor.\n";
        return true;
    }

    private function logAccess(): void
    {
        echo "Proxy: İstek zamanı kayıt altına alındı.\n";
    }
}

function clientCode(Subject $subject)
{
    $subject->request();
}

echo "İstemci: Gerçek servis nesnesi doğrudan çağrılıyor:\n";
$realSubject = new RealSubject();
clientCode($realSubject);

echo "\n";

echo "İstemci: Araya proxy nesnesi entegre ediliyor:\n";
$proxy = new Proxy($realSubject);
clientCode($proxy);
```

### Örnek Python Kodu

```python
from abc import ABC, abstractmethod

class Subject(ABC):
    @abstractmethod
    def request(self) -> None:
        pass


class RealSubject(Subject):
    def request(self) -> None:
        print("RealSubject: İstek işleniyor.")


class Proxy(Subject):
    def __init__(self, real_subject: RealSubject) -> None:
        self._real_subject = real_subject

    def request(self) -> None:
        if self.check_access():
            self._real_subject.request()
            self.log_access()

    def check_access(self) -> bool:
        print("Proxy: İstek gönderilmeden önce yetkilendirme kontrolü yapılıyor.")
        return True

    def log_access(self) -> None:
        print("Proxy: İstek zamanı kayıt altına alındı.")


def client_code(subject: Subject) -> None:
    subject.request()


if __name__ == "__main__":
    print("İstemci: Gerçek nesne çağrılıyor:")
    real_subject = RealSubject()
    client_code(real_subject)

    print("")

    print("İstemci: Proxy nesnesi çağrılıyor:")
    proxy = Proxy(real_subject)
    client_code(proxy)
```

---

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

### Proxy deseni ile Decorator deseni arasındaki en temel fark nedir?
- **Proxy:** Bir nesneye erişimi denetler veya sınırlandırır. Sarmaladığı nesnenin yaşam döngüsünü kendisi kontrol edebilir (örneğin nesneyi kendi içinde `new` ile yaratabilir veya silebilir).
- **Decorator:** Bir nesneye dinamik olarak yeni davranışlar ekler. Sarmalayacağı nesneyi dışarıdan (istemciden) hazır olarak alır; nesne yaratma sorumluluğu yoktur.

### Proxy deseni performansa ek bir yük (overhead) getirir mi?
Araya ek bir nesne ve metot çağrısı girdiği için teorik olarak mikro düzeyde bir gecikme ekler. Ancak gerçek hayatta, özellikle **Caching Proxy** ve **Virtual Proxy** kullanıldığında, gereksiz API/veritabanı sorgularını ve yoğun kaynak harcayan işlemleri engellediği için sistemin genel performansını kat kat artırır.

### Protection Proxy (Koruma Proxy'si) güvenliği tek başına sağlamak için yeterli midir?
Protection Proxy, uygulama kodu seviyesinde yetkilendirme (authorization) yapmak için mükemmel bir desendir. Ancak ağ güvenliği veya veritabanı erişim güvenliği gibi altyapısal güvenlik katmanlarının yerini tek başına alamaz. Uygulama seviyesinde rolleri (örneğin Admin/User ayrımı) kontrol etmek için kullanılır.

---

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