Structural — Yapısal Desenler
Proxy
Vekil Deseni
Amaç: Başka bir nesneye erişimi kontrol etmek için onun yerine geçen bir vekil (temsilci) nesne sağlamak.
Basit Anlatım
Teknik terim yok — günlük hayattan bir benzetme
Ünlü bir sanatçıyla görüşmek istiyorsunuz. Doğrudan sanatçıya ulaşamazsınız; önce menajeriyle konuşursunuz. Menajer, sanatçının yerine geçer: talebinizi dinler, uygun mu değil mi değerlendirir, gerekirse sanatçıya iletir, gerekmezse sizi geri çevirir.
Sizin açınızdan iletişim kurduğunuz kişi "sanatçı tarafı"dır; ama aslında araya akıllı bir kapı bekçisi konmuştur.
Kredi kartı
Alışverişte nakit yerine kredi kartı verirsiniz. Kart, banka hesabınızdaki paranın vekilidir. Satıcı için ikisi de "ödeme"dir; ama kart araya güvenlik, limit kontrolü ve kayıt tutma gibi ek işlevler katar.
Teknik Anlamı
Bir yazılımcının bakış açısıyla
Proxy, gerçek nesneyle (RealSubject) aynı arayüzü uygular ve ona bir referans tutar. İstemci farkı anlamaz. Proxy, isteği gerçek nesneye iletmeden önce veya sonra ek işlemler yapar.
Proxy türleri
- Virtual Proxy: Pahalı nesnenin oluşturulmasını gerçekten ihtiyaç duyulana kadar erteler (lazy loading).
- Protection Proxy: Yetki kontrolü yapar.
- Caching Proxy: Sonuçları önbelleğe alır.
- Remote Proxy: Uzaktaki bir nesneyi yerel bir nesneymiş gibi gösterir (gRPC / WCF istemci sınıfları).
- Logging Proxy: Çağrıları kaydeder.
Decorator'dan farkı
Yapıları çok benzerdir. Fark amaçtadır: Decorator yeni davranış ekler ve genellikle istemci tarafından iç içe kurulur. Proxy ise erişimi kontrol eder ve gerçek nesnenin yaşam döngüsünü çoğu zaman kendisi yönetir.
.NET'ten tanıdık örnekler
- Entity Framework'ün lazy loading için ürettiği proxy sınıfları.
Lazy<T>bir tür virtual proxy'dir.DispatchProxyve Castle DynamicProxy ile çalışma zamanında proxy üretimi.
C# ile Uygulama
Adım adım, çalışan kod örneği
Senaryo: Yavaş bir dış servisten belge getiriyoruz. Önüne hem yetki kontrolü hem önbellek yapan bir proxy koyacağız; ayrıca gerçek servis ihtiyaç duyulana kadar oluşturulmayacak.
Adım 1 Subject arayüzü ve gerçek nesne
public interface IDocumentService
{
string GetDocument(string id);
}
public class RemoteDocumentService : IDocumentService
{
public RemoteDocumentService() =>
Console.WriteLine(" >> Uzak sunucuya bağlantı kuruldu (pahalı işlem)");
public string GetDocument(string id)
{
Console.WriteLine($" >> Sunucudan '{id}' indiriliyor... (yavaş)");
return $"<{id} belgesinin içeriği>";
}
}Adım 2 Proxy: lazy + yetki + önbellek
İstemci için proxy, gerçek servisten ayırt edilemez çünkü aynı arayüzü uygular.
public class DocumentServiceProxy : IDocumentService
{
private RemoteDocumentService? _real; // henüz oluşturulmadı
private readonly Dictionary<string, string> _cache = new();
private readonly string _userRole;
public DocumentServiceProxy(string userRole) => _userRole = userRole;
public string GetDocument(string id)
{
// 1) Protection proxy: yetki kontrolü
if (id.StartsWith("gizli") && _userRole != "admin")
return "ERİŞİM REDDEDİLDİ";
// 2) Caching proxy: önbellekte varsa sunucuya gitme
if (_cache.TryGetValue(id, out var cached))
return cached + " (önbellekten)";
// 3) Virtual proxy: gerçek nesneyi ilk ihtiyaçta oluştur
_real ??= new RemoteDocumentService();
var doc = _real.GetDocument(id);
_cache[id] = doc;
return doc;
}
}Adım 3 Kullanım
Tüm parçaları bir araya getiren istemci (client) kodu:
IDocumentService service = new DocumentServiceProxy(userRole: "editor");
Console.WriteLine("Proxy oluşturuldu, henüz sunucuya bağlanılmadı.\n");
Console.WriteLine("1. istek: " + service.GetDocument("rapor-2026"));
Console.WriteLine("2. istek: " + service.GetDocument("rapor-2026"));
Console.WriteLine("3. istek: " + service.GetDocument("gizli-maaslar"));
IDocumentService admin = new DocumentServiceProxy(userRole: "admin");
Console.WriteLine("Admin : " + admin.GetDocument("gizli-maaslar"));Konsol çıktısı
Proxy oluşturuldu, henüz sunucuya bağlanılmadı. >> Uzak sunucuya bağlantı kuruldu (pahalı işlem) >> Sunucudan 'rapor-2026' indiriliyor... (yavaş) 1. istek: <rapor-2026 belgesinin içeriği> 2. istek: <rapor-2026 belgesinin içeriği> (önbellekten) 3. istek: ERİŞİM REDDEDİLDİ >> Uzak sunucuya bağlantı kuruldu (pahalı işlem) >> Sunucudan 'gizli-maaslar' indiriliyor... (yavaş) Admin : <gizli-maaslar belgesinin içeriği>
Kodda dikkat edilmesi gerekenler
- Sunucu bağlantısı proxy oluşturulduğunda değil, ilk gerçek istekte kuruldu.
- Aynı belge ikinci kez istendiğinde sunucuya gidilmedi.
- Yetkisiz kullanıcı için gerçek servis hiç çağrılmadı.