Proxy Tasarım Deseni Nedir?

Sayfayı kopyala
Bu yazı Design Patterns/Tasarım Desenleri Nedir? başlıklı yazı dizisinin bir parçasıdır.
Bu içerik ağırlıklı olarak refactoring.guru 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.

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, 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:
// 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
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
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
newile 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, Abstract Factory, Builder, Prototype, Singleton
Yapısal Kalıplar (Structural Patterns)
Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy
Davranışsal Kalıplar (Behavioral Patterns)
Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor
