Decorator ve Adapter: Yapısal Desenlerle Sarmalama
Beceri rehberi

Decorator ve Adapter: Yapısal Desenlerle Sarmalama

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

Adapter ile uyumsuz arayüzleri bağlayın, Decorator ile davranış ekleyin: kod örnekleri, Proxy ile farkı, zincir sırası ve sık yapılan hatalar.

Yapısal desenler ne işe yarar, Decorator ve Adapter neden birlikte öğrenilir?

Yapısal tasarım desenleri, nesnelerin ve sınıfların nasıl bir araya getirileceğiyle ilgilenir. Decorator ve Adapter bu ailenin en sık kullanılan üyelerindendir ve her biri bir nesneyi sararak çalışır. Fark, sarmanın amacındadır: Adapter uyumsuz arayüzleri birbirine bağlar, Decorator ise aynı arayüzü koruyarak nesneye yeni davranış ekler.

Bu ayrım uygulamada önemlidir. Elinizde kendi sisteminizin beklediği arayüze uymayan bir dış kütüphane ya da eski bir servis varsa ihtiyacınız Adapter'dır. Mevcut bir nesnenin davranışına günlük kaydı, önbellek, yetki kontrolü ya da yeniden deneme gibi eklemeler yapmak istiyorsanız ihtiyacınız Decorator'dır.

İkisinin de ortak kazancı, çağıran kodu değiştirmeden çalışmaktır: çağıran yalnızca hedef arayüzü bilir, arkada ne olduğunu bilmez. Bu da SOLID prensiplerinden açık/kapalı ve bağımlılığı tersine çevirme fikirlerinin pratik karşılığıdır.

Adapter: uyumsuz arayüzü köprülemek

Örneğin uygulamanız ödemeyi kendi tanımladığı PaymentService arayüzü üzerinden alıyor, ama yeni bağlanacağınız sağlayıcının kütüphanesi farklı metot adları ve farklı veri biçimi kullanıyor. Kütüphaneyi uygulamanın her yerinde doğrudan kullanmak, sağlayıcıyı değiştirdiğiniz gün her yeri değiştirmek demektir. Bunun yerine bir adaptör yazarsınız:

interface PaymentService { charge(amount: number, cardInfo: Card): PaymentResult; }

class ProviderAdapter implements PaymentService { constructor(private client: ProviderLibrary) {} charge(amount: number, card: Card): PaymentResult { const response = this.client.process({ amount: amount, cardNo: card.number }); return { success: response.status === "ok", reference: response.transactionId }; } }

Adaptör şu işleri yapar: çağrıyı çevirir (metot ve parametre adları), veriyi dönüştürür (tutar biçimi, tarih biçimi) ve hataları sizin hata modelinize çevirir. Sağlayıcı değiştiğinde yalnızca yeni bir adaptör yazılır, uygulamanın geri kalanı etkilenmez.

İyi bir adaptör ince kalır. İçine iş kuralı koyarsanız dış sistemin yapısı sizin alan modelinize sızar. Dış sisteme ait her şeyin adaptörde bitmesi gerekir. Bu fikir, sistemin sınırlarında arayüz-uyarlayıcı çifti kuran hexagonal mimarinin de temelidir.

Decorator: aynı arayüzü koruyarak davranış eklemek

Decorator, bir nesneyi aynı arayüzü gerçekleyen başka bir nesneyle sarar ve çağrıyı iletmeden önce ya da sonra ek iş yapar. Kalıtım yerine bileşimi kullandığı için davranışlar çalışma zamanında istenen kombinasyonda istiflenebilir.

Örneğin bir müşteri depolama sınıfına önce günlük kaydı, sonra önbellek eklemek isteyelim:

interface CustomerStore { find(id: string): Customer; }

class DatabaseStore implements CustomerStore { /* gerçek okuma */ }

class CachedStore implements CustomerStore { constructor(private inner: CustomerStore, private cache: Map<string, Customer>) {} find(id: string): Customer { const existing = this.cache.get(id); if (existing) return existing; const result = this.inner.find(id); this.cache.set(id, result); return result; } }

class LoggingStore implements CustomerStore { constructor(private inner: CustomerStore, private logger: Logger) {} find(id: string): Customer { this.logger.info("Müşteri aranıyor: " + id); return this.inner.find(id); } }

Kurulum noktasında istifleme yapılır:

const store = new LoggingStore(new CachedStore(new DatabaseStore(), new Map()), logger);

Çağıran sınıf yalnızca CustomerStore görür. Yarın önbelleği çıkarmak ya da araya yetki kontrolü eklemek, sınıfın kendisine dokunmadan kurulumu değiştirmekle olur.

Decorator, Adapter ve Proxy nasıl ayrılır?

Bu desenlerin hepsi bir nesneyi sarmaya dayanır; niyetleri farklıdır.

Ölçüt: Arayüz ilişkisi. Adapter: Sarılan nesnenin arayüzünden farklı bir arayüz sunar. Decorator: Sarılan nesneyle aynı arayüzü sunar. Proxy: Sarılan nesneyle aynı arayüzü sunar.

Ölçüt: Amaç. Adapter: Uyumsuzluğu gidermek. Decorator: Yeni sorumluluk eklemek ve istiflemek. Proxy: Erişimi denetlemek, gecikmeli yüklemek ya da uzaktaki nesneyi yerel gibi göstermek.

Ölçüt: İstiflenebilirlik. Adapter: Genellikle tek katman. Decorator: Birden çok katman doğaldır. Proxy: Genellikle tek katman.

Pratikte sınırlar bulanıklaşabilir. Önbellekli bir sarmalayıcı bir bakıma hem Decorator hem Proxy sayılabilir. Önemli olan etiket değil, kodunuzu okuyan kişinin sarmalayıcının neden orada olduğunu anlayabilmesidir; sınıfa niyetini söyleyen bir ad vermek bu yüzden önemlidir.

Decorator zincirinde sıranın önemi

Dekoratörleri istiflerken sıra davranışı değiştirir. Yukarıdaki örnekte günlük dekoratörü dışta, önbellek içte olduğunda günlük her çağrıyı kaydeder, önbellekten gelse bile. Sıra tersine çevrilirse yalnızca önbelleğe ıskalayan çağrılar kaydedilir. Hangisinin doğru olduğu ihtiyaca bağlıdır, ama bu bilinçli bir karar olmalı.

Yaygın bir hata, yetki kontrolünü önbelleğin içine koymaktır: önbellek daha önce yetkili biri için getirdiği veriyi yetkisiz kişiye de sunabilir. Güvenlikle ilgili dekoratörler genellikle en dışta durur. Yeniden deneme dekoratörünü önbelleğin dışına koymak ise başarısız bir okumanın gereksiz yere tekrarlanmasını önler.

Zinciri okunabilir tutmak için kurulumu tek bir yerde, sırayı açıkça gösteren bir biçimde yazın ve ekibin sırayı değiştirmeden önce testle doğrulayabileceği bir kurulum testi bulundurun.

Sık yapılan hatalar

  • Adaptöre iş kuralı yüklemek: Adaptör çevirir; karar vermez. İş mantığı alan katmanında kalmalıdır.
  • Her ek özellik için alt sınıf üretmek: Günlüklü, önbellekli, günlüklü ve önbellekli gibi kombinasyonlar kalıtımla patlar. Decorator tam bu durum için vardır.
  • Dekoratörlerde arayüzü şişirmek: Arayüz çok metotluysa her dekoratör hepsini iletmek zorunda kalır. Arayüzü küçük tutmak ya da yalnızca ilgili metodu sarmak gerekir.
  • Dış kütüphane tiplerini sızdırmak: Adaptör dönüş tiplerinde kütüphanenin sınıflarını görünür bırakırsa uygulamanın geri kalanı yine o kütüphaneye bağımlı olur.
  • Dekoratörün durumunu paylaşmak: Önbellek gibi paylaşılan durumu eşzamanlı çağrılarda korumadan bırakmak hata üretir.
  • Testi atlamak: Her dekoratörün ve adaptörün, sahte bir iç nesneyle birim testiyle sınanması, deseni sürdürülebilir kılar.

Bu beceriyi Mindset programında nerede çalışırsınız?

Yazılım Mimarisi ve Tasarım Desenleri programında yapısal tasarım desenleri ayrı bir modül olarak işlenir; Decorator ve Adapter bu modülün temel konularındandır. Program, dış servis entegrasyonlarıyla ve sürekli büyüyen kod tabanlarıyla çalışan geliştiriciler ile mimari kararları gözden geçiren teknik liderler için, desenleri bağlamıyla birlikte değerlendirme becerisi kazandırmaya yöneliktir.

Entegrasyon yoğun kurumlarda ekipler, dış sistem sınırlarını adaptörlerle çizme ve ortak davranışları (günlük, önbellek, yetki) dekoratörlerle katmanlama konusunda ortak bir dil kurduğunda kod incelemesi ve sorun çözme süreçleri belirgin biçimde kolaylaşır.

İlgili Mindset programı

Yazılım Mimarisi ve Tasarım Desenleri

Sık sorulanlar

Sık sorulan sorular

Decorator ile Adapter arasındaki temel fark nedir?

Adapter, uyumsuz arayüzleri birbirine bağlar: sarılan nesnenin arayüzünden farklı bir arayüz sunar. Decorator ise sarılan nesneyle aynı arayüzü korur ve çağrıya ek davranış katar. Dış kütüphaneyi kendi arayüzünüze uydurmak istiyorsanız Adapter, mevcut bir sınıfa günlük ya da önbellek eklemek istiyorsanız Decorator kullanırsınız.

Decorator yerine kalıtım kullanmak neden sorun olur?

Her özellik kombinasyonu için ayrı bir alt sınıf gerekir: günlüklü, önbellekli, hem günlüklü hem önbellekli gibi. Eklenen her özellik alt sınıf sayısını katlar ve davranışlar derleme zamanında sabitlenir. Decorator ile aynı davranışları çalışma zamanında istenen sırada istifleyebilir, kombinasyonları yeni sınıf yazmadan kurabilirsiniz.

Adapter yazarken nelere dikkat etmeliyim?

Adaptörü ince tutun: yalnızca çağrıyı, veriyi ve hata biçimini çevirsin. Dış kütüphanenin tiplerini dönüş değerlerinde sızdırmayın, iş kuralını içine koymayın. Böylece sağlayıcı değiştiğinde yalnızca adaptör yeniden yazılır. Adaptörü sahte bir istemciyle sınamak, çeviri hatalarını erken yakalamanın en kolay yoludur.

Decorator zincirinde sıra neden önemlidir?

Sıra, davranışın hangi çağrılara uygulandığını belirler. Önbelleğin dışındaki bir günlük dekoratörü her çağrıyı kaydeder, içindeki ise yalnızca önbelleğe ıskalayanları. Yetki kontrolü gibi güvenlik dekoratörleri genellikle en dışta durur, aksi halde önbellek yetkisiz kişiye veri sunabilir. Sırayı bilinçli seçin ve bir kurulum testiyle sabitleyin.

Bu desenleri her projede kullanmalı mıyım?

Hayır. Dış sistemle entegrasyon ya da eklenebilir çapraz davranış ihtiyacı yoksa gereksiz katman yaratırlar. Belirti olarak bir dış arayüzün kodun her yerine yayılması ya da aynı ek davranışın birçok sınıfta kopyalanması desen ihtiyacını gösterir. İhtiyaç belirginleşmeden eklenen sarmalayıcılar kodu okunaksız hale getirir.

Decorator ve Adapter Desenleri Nasıl Uygulanır?