Tasarım Desenleri Terimler Sözlüğü Design Patterns Glossary

Bu bölümde ki terimleri ezberlemenize gerek yoktur.
Konular içerisinde ki terimlerdir, sadece konuyu daha iyi anlamanıza yardımcı olması için eklenmiştir.

Pattern (Desen)

Yazılım mimarisi bağlamında, belirli bir bağlamda sıkça karşılaşılan bir soruna kanıtlanmış, yeniden kullanılabilir ve iyi tanımlanmış bir çözüm sunan yapısal dil.

Creational Patterns (Oluşturucu Desenler)

Nesnelerin yaratılma (instantiation) süreçlerini soyutlayan desenler. Singleton, Factory Method, Builder, Abstract Factory, Prototype desenlerini içerir.

Structural Patterns (Yapısal Desenler)

Nesnelerin birbirleriyle ilişkilerini ve yapılarını organize eden desenler. Adapter, Bridge, Composite, Decorator, Facade, Proxy, Flyweight desenlerini içerir.

Behavioral Patterns (Davranışsal Desenler)

Nesneler arasındaki karmaşık etkileşimleri, iletişimi ve sorumluluk akışını organize eden desenler. Observer, Strategy, State, Template Method, Visitor gibi desenleri içerir.

Singleton

Bir sınıftan yalnızca tek bir örnek (instance) yaratılmasını garanti eden desen. Kaynağın paylaşımını ve kontrolünü merkezileştirir.

Factory Method

Nesne yaratma işlemini alt sınıflara devreden desen. İstemcinin hangi sınıfın yaratılacağını bilmeden nesne yaratmasını sağlar.

Builder

Karmaşık nesneleri adım adım yaratan desen. Aynı yaratma süreciyle farklı gösterimler elde edilmesini sağlar.

Abstract Factory

İlişkili nesne ailelerini yaratmak için bir arayüz sağlayan desen. Somut fabrikalar farklı nesne ailelerini üretir.

Prototype

Yeni nesneleri klonlama yoluyla yaratan desen. Pahalı yaratma işlemlerinden kaçınmak için mevcut nesneleri kopyalar.

Adapter

Uyumsuz arayüzleri uyumlu hale getiren desen. Bir sınıfın arayüzünü istemcinin beklediği arayüze dönüştürür.

Bridge

Bir soyutlamayı uygulamasından ayırarak ikisinin de bağımsız olarak değişebilmesini sağlayan desen.

Composite

Nesneleri ağaç yapıları halinde organize eden desen. Tekil nesneleri ve bileşimleri aynı şekilde işlemeye olanak tanır.

Decorator

Nesnelere dinamik olarak yeni sorumluluklar ekleyen desen. Kalıtımdan daha esnek bir alternatif sunar.

Facade

Karmaşık bir alt sisteme basitleştirilmiş bir arayüz sağlayan desen. Alt sistemin karmaşıklığını gizler.

Proxy

Başka bir nesneye erişimi kontrol eden veya ona bir alternatif sağlayan desen. Lazy loading, erişim kontrolü gibi amaçlarla kullanılır.

Flyweight

Çok sayıda benzer nesneyi verimli bir şekilde desteklemek için paylaşılan durumu kullanan desen. Bellek kullanımını optimize eder.

Observer

Bir nesnenin durumu değiştiğinde ona bağımlı tüm nesneleri otomatik olarak bilgilendiren desen. Yayıncı-abone (publish-subscribe) mekanizması sağlar.

Strategy

Bir algoritma ailesini tanımlayan ve bunları değiştirilebilir hale getiren desen. Çalışma zamanında algoritma seçimine izin verir.

State

Bir nesnenin iç durumu değiştiğinde davranışını değiştirmesine izin veren desen. Durum geçişlerini yönetir.

Template Method

Bir algoritmanın iskeletini bir metotta tanımlayan desen. Bazı adımları alt sınıflara devreder. Algoritma yapısını korurken özelleştirmeye izin verir.

Visitor

Bir nesne yapısındaki öğeler üzerinde yeni işlemler tanımlamayı sağlayan desen. Yapıyı değiştirmeden yeni operasyonlar ekler.

Memento

Bir nesnenin iç durumunu dışa açıklamadan kaydetmesine ve geri yüklemesine izin veren desen. Undo/redo işlemleri için kullanılır.

Command

İstekleri nesneler halinde kapsülleyen desen. İstekleri parametreleştirmeyi, kuyruğa almayı veya loglamayı sağlar.

Iterator

Bir koleksiyonun öğelerine sırayla erişmek için bir yol sağlayan desen. Koleksiyonun iç yapısını gizler.

Mediator

Nesneler arasındaki karmaşık etkileşimleri merkezi bir aracı (mediator) üzerinden yöneten desen. Nesneler arası doğrudan bağımlılıkları azaltır.

Chain of Responsibility

Bir isteği bir alıcı zinciri boyunca geçiren desen. Her alıcı isteği işleyebilir veya bir sonrakine iletebilir.

Tight Coupling (Sıkı Bağlılık)

Nesnelerin birbirine sıkı sıkıya bağımlı olduğu durum. Bir nesnedeki değişiklik diğerlerini etkiler. Esnekliği azaltır.

Loose Coupling (Gevşek Bağlılık)

Nesnelerin birbirine zayıf bağımlılıkla bağlandığı durum. Değişikliklerin yayılmasını önler. İstenen bir özelliktir.

Inversion of Control (IoC)

Kontrolün tersine çevrilmesi prensibi. Geleneksel akış yerine, bağımlılıklar dışarıdan sağlanır. Nesne yaratma kontrolünü framework'e devreder.

Delegation (Yetki Devri)

Bir nesnenin, bir işi başka bir nesneye devretmesi. Kalıtımdan daha esnek bir alternatif sunar. Kompozisyon ile birlikte kullanılır.

Composition (Bileşim)

Nesneleri birleştirerek daha karmaşık davranışlar oluşturma. Kalıtıma tercih edilen yaklaşım. "Has-a" ilişkisi.

Inheritance (Kalıtım)

Bir sınıfın başka bir sınıftan özellik ve davranışları miras alması. "Is-a" ilişkisi. Esneklik açısından kompozisyondan daha sınırlıdır.

Abstract Class (Soyut Sınıf)

Doğrudan örneklenemeyen, ancak alt sınıfların türetilebileceği sınıf. Ortak davranışları tanımlar, bazı metodları soyut bırakır.

Interface (Arayüz)

Bir sınıfın uyması gereken sözleşmeyi tanımlayan yapı. Hangi metodların uygulanması gerektiğini belirtir. Çoklu kalıtım için kullanılır.

Concrete Class (Somut Sınıf)

Doğrudan örneklenebilen sınıf. Tüm soyut metodları uygulamış olmalıdır. Gerçek implementasyonu içerir.

Context (Bağlam)

Desenin çalıştığı ortamı temsil eden nesne. İstemci ile desen arasında köprü görevi görür. Durum veya strateji nesnesine referans tutar.

Subject (Konu)

Observer deseninde, gözlemcileri yöneten nesne. Durum değişikliklerini gözlemcilere bildirir. Arayüz tanımlar ve gözlemci listesini tutar.

Observer (Gözlemci)

Observer deseninde, konunun durum değişikliklerinden haberdar olan nesne. guncelle() metodu ile bildirim alır.

Originator (Oluşturan)

Memento deseninde, durumu kaydetmek veya geri yüklemek istenen nesne. Hem bir Memento yaratma hem de geri yükleme metoduna sahiptir.

Caretaker (Vasi)

Memento deseninde, Memento nesnelerini saklayan ve geçmişi yöneten nesne. Originator'dan gelen isteklere göre doğru zamanda Memento'yu geri verir.

Memento (Hatıra)

Memento deseninde, Originator nesnesinin dahili durumunun anlık görüntüsünü tutan nesne. Durumu değiştirilemez (immutable) şekilde saklar.

Hook Method (Kanca Metodu)

Template Method deseninde, varsayılan (genellikle boş) bir uygulama sunan metot. Alt sınıfların isteğe bağlı olarak geçersiz kılmasına izin verir.

Template Method (Şablon Metodu)

Algoritmanın iskeletini içeren final (alt sınıflar tarafından değiştirilemez) metot. Algoritmanın adımlarını sırayla çağırır.

Class Pattern (Sınıf Deseni)

Kalıtımı kullanan desenler. Derleme zamanında ilişkiler belirlenir. Daha az esnektir ancak daha statik yapı sağlar.

Object Pattern (Nesne Deseni)

Kompozisyon ve yetki devrini kullanan desenler. Çalışma zamanında (runtime) dinamik olarak değiştirilebilir. Daha esnektir. GoF desenlerinin çoğu bu kategoridedir.

Gang of Four (GoF)

Design Patterns kitabını yazan dört yazar: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. 1994'te yazılım desenlerini kataloglayan klasik eser.

Shared Vocabulary (Ortak Söz Varlığı)

Desenlerin sağladığı ortak dil. Ekip içi iletişimi hızlandırır. Uzun mimari açıklamaları tek bir terime indirger. GoF'un en büyük katkısıdır.

JavaScript'te Tasarım Desenleri

Tasarım Desenleri Ana Konusu Detaylı Açıklamaları

Tasarım desenleri, JavaScript'te kod yapısını daha modüler, okunaklı ve bakımı kolay hale getirmek için kullanılan kanıtlanmış çözümlerdir. Bu bölümde, tasarım desenlerinin ana konularını detaylı açıklamalarıyla inceleyeceğiz.

Ana Konu Felsefi ve Tarihsel Açıklama

Tasarım Desenleri Uygulamaları Ana Konu Detaylı Açıklamaları

Mimari Miras: Christopher Alexander'dan Yazılım Mühendisliğine

Tasarım desenleri, kökenini fiziksel mimariden alan ve yazılım dünyasında sıkça tekrarlanan problemlere sunulan

evrensel ve kanıtlanmış stratejilerdir.

Bu kavram, Christopher Alexander’ın "sorunların her zaman bir bağlam içinde tekrar ettiği" felsefesine dayanır.

Yazılım mühendisliğinde bir desen; sadece hazır bir kod parçası değil, belirli bir tasarım probleminin çözümü için kullanılan

"zihinsel bir şablon" ve mimari bir rehberdir.

Kodun sadece anlık olarak çalışmasını değil, sistemin geneline yayılan bir

mantıksal bütünlük kazanmasını sağlar.

Tasarım Desenlerinin Temel İşlevi ve Mühendislik Değeri

Desenlerin birincil görevi, yazılım bileşenleri arasındaki etkileşimi standardize ederek sistemi "değişime dirençli" hale getirmektir.

Bu yaklaşım, sistemin karmaşıklığını yönetilebilir parçalara böler ve bakım maliyetlerini minimize eder.

Yeniden Kullanılabilirlik: Bir desen, binlerce mühendisin deneyimiyle damıtılmış bir çözüm sunduğu için, tekerleği yeniden icat etmek yerine standartlaşmış bir mühendislik bilgeliğini projeye entegre etmenizi sağlar.

Ortak İletişim Dili: Desenler, geliştiriciler arasında yüksek seviyeli bir soyutlama dili oluşturur.

Bir ekibin "Burada bir gözlemci yapısı kuralım" demesi, karmaşık bir mekanizmanın tüm detaylarını tek bir terimle hata payı bırakmadanaktarmasını sağlar.

Soyutlama ve Esneklik: Sıkı Bağlılıktan Kurtulma

İyi bir tasarım deseninin en büyük başarısı, sistemin parçaları arasındaki sıkı bağlılığı koparmasıdır.

Bileşenlerin birbirlerinin iç detaylarından bağımsız kalmasını sağlayarak, bir noktada yapılan değişikliğin tüm sistemi çökertme riskini ortadan kaldırır.

Bu mimari disiplin, Soyutlama katmanlarını kullanarak mantığın uygulamadan ayırır.

Sonuç olarak, tasarım desenleri sadece teknik bir zorunluluk değil, yazılımı sürdürülebilir bir sanata dönüştüren stratejik bir

düşünme biçimidir.

Oluşturucu Desenler (Creational Patterns) Genel Bilgi

Genel Bilgi: Yaratım Süreçlerinin Soyutlanması

Oluşturucu Desenler, sistemin esnekliğini ve sürdürülebilirliğini sağlamak amacıyla nesnelerin yaratılma ( "instantiation" ) süreçlerini soyutlamakla ilgilenir.

Bu desenlerin temel stratejik amacı, bir sistemi, hangi somut sınıfların ( concrete classes ) kullanıldığı bilgisinden tamamen yalıtmaktır.

Temelde, doğrudan new operatörünü kullanmanın getirdiği sıkı bağlılık riskini ortadan kaldırır ve Inversion of Control prensibini nesne yaratma düzeyinde hayata geçirir.

Temel Felsefesi: Yaratımda Bağımsızlık

Oluşturucu Desenler, sistemin yaratma mantığı ( what/how to create ) ile bu nesneleri kullanma mantığını birbirinden net bir şekilde ayırır.

Yaratım Akışını Kontrol Etme: Nesnelerin nasıl oluşturulacağına dair tüm mantığı ( sınıf seçimi , örnek sayısı, yapılandırma adımları ) merkezi bir noktaya ( Fabrika, Builder veya Singleton ) taşıyarak karmaşıklığı istemciden gizler.

Çalışma Zamanı Esnekliği ve Yapısal Bütünlük

Doğrudan sınıf adı yerine bir arayüze bağımlılık kurarak, yaratılacak somut sınıfın kararını derleme zamanından çalışma zamanına erteler.

Bu esneklik, yeni ürün sınıfları eklendiğinde mevcut istemci koduna dokunmadan sistemin genişlemesini sağlar; bu durum sistemin ölçeklenebilirliğini artırır.

Özellikle Singleton ve Builder gibi desenler, nesnelerin yaşam döngüsünü bizzat yöneterek, yaratılan objelerin yapısal olarak her zaman doğru ve tutarlı olmasını garanti eder.

Sonuç olarak Oluşturucu Desenler, yazılımın iskeletini kurarken nesneleri sadece "üretmek" değil, onları bir mimari disiplin içerisinde sisteme dahil etmekle görevlidir.

Singleton Deseni (Tekil Nesne) Örnek Uygulama ve Detaylı Açıklama

Tekil Nesne: Mutlak Kontrol ve Global Erişim

Singleton deseni, bir sınıftan uygulamanın tüm yaşam döngüsü boyunca yalnızca ve yalnızca bir adet nesne örneği ( instance ) oluşturulmasını garanti eden ve bu tekil örneğe her noktadan ulaşılabilen global bir erişim noktası sunan yapısal bir güvencedir.

Felsefi Amaç: Bu desen, bir kaynağın ( veritabanı bağlantı havuzu , konfigürasyon yöneticisi veya

merkezi loglama servisi ) birden fazla kez başlatılmasının donanım açısından maliyetli olduğu veya mantıksal olarak veri tutarsızlığı yaratacağı senaryolarda devreye girer.

Singleton, paylaşılan kaynağın kontrolünü merkezileştirerek kaynak israfını önler ve uygulamanın farklı katmanlarının aynı güncel veriyle senkronize kalmasını sağlar.

Modern JavaScript ve Uygulama Sınırları

JavaScript ekosisteminde Singleton, genellikle statik metotlar veya modül seviyesindeki "Closures" (kapanımlar) kullanılarak inşa edilir.

Modern Yaklaşım: Günümüzde ES Modülleri (import/export), varsayılan olarak her modül için tek bir örnek yarattığı için Singleton deseni sıklıkla bu modül kapsamı üzerinden doğal bir şekilde taklit edilir.

Ancak karmaşık nesne hiyerarşilerinde defansif programlama kuralları hala klasik sınıf yapılarını zorunlu kılar.

Yöntem: Sınıf ve Statik Kontrol (Klasik OOP)

Bu yöntem, class mimarisini kullanarak, özellikle constructor (yapılandırıcı) içinde kurulan bir denetim mekanizmasıyla dışarıdan bilinçsizce yeni örnek oluşturulmasını fiziksel olarak engeller.

Bu uygulama, desenin kurallarını dil seviyesinde zorlayan "Savunmacı" ( defensive ) bir mühendislik yaklaşımıdır ve sistemin yanlışlıkla çoklu nesne üretip belleği şişirmesine engel olur.

Mekanizma: Çift Kontrollü Yapı

Klasik OOP Singleton modelinde güvenlik iki aşamalı bir bariyerle sağlanır:

1. Dahili Kontrol (Constructor Sınırlaması): Yapılandırıcı metot, sınıfın statik instance özelliğini kontrol eder.

Eğer bir örnek zaten bellekte mevcutsa, constructor hemen bir hata ( Error ) fırlatarak veya mevcut örneği döndürerek yeni bir yaratımı bloke eder.

2. Harici Erişim (getInstance): Sınıfın yaratılmasına ve paylaşılmasına izin veren yegane kanal, statik olarak tanımlanmış getInstance() metodudur.

Bu metot, referansı kontrol eder; nesne yoksa yalnızca bir kez üretir, varsa mevcut olanı sunar.

Yöntem 1 Sınıf ve Statik Kontrol ile Singleton Örneği

class KonfigurasyonYoneticisi {
    // Private field - dışarıdan erişilemez
    static #instance; 

    constructor() {
        if (KonfigurasyonYoneticisi.#instance) {
            return KonfigurasyonYoneticisi.#instance;
        }
        
        this.ayarlar = { tema: 'dark', dil: 'tr' };
        KonfigurasyonYoneticisi.#instance = this;
    }

    // Tekil örneğe erişim
    static getInstance() {
        return KonfigurasyonYoneticisi.#instance || new KonfigurasyonYoneticisi();
    }

    getAyar(key) {
        return this.ayarlar[key];
    }
}

// Kullanım
const ayar1 = KonfigurasyonYoneticisi.getInstance();
const ayar2 = KonfigurasyonYoneticisi.getInstance();

console.log(ayar1 === ayar2); // true - aynı instance

// Artık new ile çağrılsa bile tek instance döner
const ayar3 = new KonfigurasyonYoneticisi();
console.log(ayar1 === ayar3); // true - hala aynı instance

Yöntem 2 Modül Singleton (Modern ES Modülleri) Örneği

// logger.js - Bu modül, uygulandığı her yerde tek bir örnektir.

let logSayisi = 0; // Bu değişken modül kapsamı içinde korunur (private gibi)

class Logger {
    constructor() {
        this.id = Math.random().toString(16).slice(2, 6);
    }

    log(mesaj) {
        logSayisi++; // Paylaşılan statik sayacı günceller
        console.log(`[ID: ${this.id}, #${logSayisi}] ${mesaj}`);
    }
}

// 💡 Tek Örnek Yaratılır ve Dışa Aktarılır
const loggerInstance = new Logger();

export default loggerInstance;
                 

// app.js
import logger from './logger.js'; 
import { logIslem } from './component.js'; // Başka bir modülden çağrı

logger.log("Uygulama Başlatıldı"); // Log Sayısı: 1
logIslem();                       // Log Sayısı: 2 (Component'ten geldi)
logger.log("Ana İşlem Bitti");   // Log Sayısı: 3

// component.js içinde de aynı logger objesi kullanılmaktadır.
                  

Fabrika Metodu Deseni (Factory Method Pattern) Örnek Uygulama ve Detaylı Açıklama

Nesne Yaratımının Soyutlanması

Fabrika Metodu Deseni, bir nesnenin yaratılma mantığını, o nesneyi fiilen kullanan istemci kodundan ( client code ) tamamen soyutlamak ve gizlemek için kullanılır.

Bu desen, bir üst sınıfın bir nesneyi oluşturma sorumluluğunu doğrudan üstlenmek yerine, bu kararı ve üretim sürecini

alt sınıflara ( subclasses ) devretmesine olanak tanıyan esnek bir hiyerarşi kurar.

Felsefi Amaç: Kontrolün Tersine Çevrilmesi (IoC)

Fabrika deseninin temel vizyonu, sistem bileşenleri arasında gevşek bağlılık ( loose coupling ) sağlamaktır.

Geliştirme sürecinde doğrudan new SomutSinif() komutunu kullanmak, istemci kodunu o somut sınıfa göbekten bağlar.

Bu sıkı bağlılık ( tight coupling ), yeni bir ürün türü eklendiğinde veya mevcut bir tip değiştirildiğinde, projedeki tüm new çağrılarını tek tek bulup düzeltme zorunluluğu doğurur.

Bu durum hem bakım maliyetini artırır hem de insan hatasına bağlı sistem kırılmalarına davetiye çıkarır.

Mühendislik Çözümü ve Polimorfizm

Çözüm: Fabrika Metodu, nesne yaratma yetkisini bir arayüze veya soyut bir fabrikaya ( Factory ) devreder. İstemci artık sadece fabrika ile iletişim kurar; fabrika ise arka planda hangi somut ürünün seçileceğine ve nasıl yapılandırılacağına dair tüm karmaşık mantığı kapsüller.

Bu mimari yaklaşım, bağımlılıkların karar anını "kod yazım aşamasından" ( compile-time ), uygulamanın "çalışma anına" ( runtime ) erteler.

Polimorfizm Desteği: Fabrika Metodu, oluşturucu desenler arasında Polimorfizmi en güçlü şekilde destekleyen yapıdır.

Alt sınıflar, üst sınıftaki fabrika metodunu geçersiz kılarak ( override ), istemci tarafında hiçbir kod değişikliği yapılmasına gerek kalmadan farklı ve özelleşmiş somut ürünler üretebilirler.

Sonuç olarak bu desen, yazılımın genişleme kapasitesini artırırken, mevcut iskeletin bozulmadan kalmasını sağlayan profesyonel bir yaratım stratejisidir.

Factory Method Pattern Fabrika Metodu Deseni Örneği

// 1. Ürün Temel Sınıfı
class Bildirim {
    gonder(mesaj) {
        throw new Error("Bu metot alt sınıflarda uygulanmalıdır.");
    }
}

// 2. Somut Ürünler
class EmailBildirimi extends Bildirim {
    gonder(mesaj) {
        console.log(`[EMAIL] Gönderiliyor: ${mesaj}`);
    }
}

class SMSBildirimi extends Bildirim {
    gonder(mesaj) {
        console.warn(`[SMS] Hızlı Uyarı: ${mesaj}`);
    }
}

// 3. Fabrika Sınıfı (Static Metot Kullanımı)
class BildirimFabrikasi {
    // 💡 Fabrika Metodu: Yaratılacak nesnenin tipine karar verir.
    static createBildirim(tip) {
        switch (tip) {
            case 'email':
                return new EmailBildirimi();
            case 'sms':
                return new SMSBildirimi();
            default:
                throw new Error(`Bilinmeyen bildirim tipi: ${tip}`);
        }
    }
}

// 4. İstemci Kodu (Client Code)
// İstemci, doğrudan new EmailBildirimi() kullanmak yerine Fabrika'yı kullanır.
const emailGonderici = BildirimFabrikasi.createBildirim('email');
const smsGonderici = BildirimFabrikasi.createBildirim('sms');

emailGonderici.gonder("Yeni rapor hazır."); 
smsGonderici.gonder("Acil durum!");
                          

Builder Deseni (Kurucu/İnşa Edici Desen) Örnek Uygulama ve Detaylı Açıklama

Karmaşık Nesnelerin Sistematik İnşası

Builder Deseni, karmaşık nesnelerin yaratılma süreçlerini basitleştirmek, kodun okunabilirliğini artırmak ve üretim aşamalarını standartlaştırmak için kullanılan bir mimari çözümdür.

Bir nesnenin farklı temsillerini (versiyonlarını) oluşturma ihtiyacı duyulduğunda, ancak bu yaratım sürecinin her seferinde

aynı mantıksal adımları izlemesi gerektiğinde ideal bir performans sergiler.

Bu desen, özellikle çok sayıda isteğe bağlı parametreye sahip olan objelerin güvenli, aşamalı ve son derece okunaklı bir şekilde inşa edilmesini sağlar.

Felsefi Amaç: Kontrollü ve Parçalı Üretim

Builder deseninin temel felsefesi, bir nesneniniç yapısını oluşturma mantığı ile bu nesnenin farklı parçalarını bir araya getirme mantığını birbirinden kesin çizgilerle ayırmaktır.

Problem (Telescoping Constructor): Eğer bir sınıfa ait yapılandırıcı (constructor) metodu çok fazla opsiyonel parametre alıyorsa

( 10'dan fazla ), bu parametrelerin sırasını takip etmek imkansız hale gelir.

Geliştiricinin yanlış sırada veri girmesi, sistemin sessizce hatalı çalışmasına veya tamamen kırılmasına neden olur.

Çözüm: Aşamalı Yapılandırma ve Tutarlılık

Mühendislik Çözümü: Builder, bu kaosu ortadan kaldırır. Karmaşık nesne, büyük bir blok halinde değil, adım adım ( step-by-step ) oluşturulur.

Bu yaklaşım, geliştiricinin isteğe bağlı bileşenleri sadece ihtiyaç duyulduğu anlarda eklemesini sağlar ve tüm yWaratım sürecini zincirleme ( chaining ) bir yapıya dönüştürerek kodun şiirsel bir akıcılık kazanmasını sağlar.

Yapısal Garanti: Bu yöntem, nesnenin tutarlılığını ( validity ) en üst düzeyde korur.

Çünkü nesne, ancak tüm zorunlu adımlar hatasız geçildikten sonra build() metodu ile nihai ve güvenli formuna kavuşur.

Sonuç olarak Builder, karmaşıklığı yönetilebilir adımlara bölen ve nesne üretimini bir "montaj hattı" disiplinine kavuşturan üst düzey bir tasarım standardıdır.

Builder Method Pattern Builder Deseni Örneği

// 1. Ürün (Product): İnşa edilen nesne
class Rapor {
    constructor(bolumler) {
        this.bolumler = bolumler;
    }

    goster() {
        console.log("--- RAPOR İÇERİĞİ ---");
        this.bolumler.forEach(b => console.log(`- ${b.tip}: ${b.icerik}`));
        console.log("-----------------------");
    }
}

// 2. ve 3. Builder/Somut Builder: İnşa adımlarını kapsüller ve Director görevini üstlenir
class RaporBuilder {
    constructor() {
        this.reset();
    }

    // Builder'ı sıfırlama metodu
    reset() {
        this.bolumler = [];
        this.baslik = "Varsayılan Başlık";
    }

    // Adım 1: Basit bileşen ekleme (Chaining için 'this' döndürülür)
    baslikEkle(metin) {
        this.baslik = metin;
        return this; // 👈 Zincirleme için kritik
    }

    // Adım 2: İsteğe bağlı bileşen ekleme
    grafikEkle(veri) {
        this.bolumler.push({ tip: "Grafik", icerik: `Veri Seti (${veri})` });
        return this;
    }

    // Adım 3: Zorunlu bileşen ekleme
    ozetEkle(metin) {
        this.bolumler.push({ tip: "Özet", icerik: metin });
        return this;
    }

    // Nihai Metot: Ürünü oluşturur ve Builder'ı sıfırlar.
    build() {
        this.bolumler.unshift({ tip: "Başlık", icerik: this.baslik });
        const nihaiRapor = new Rapor(this.bolumler);
        this.reset(); // Builder'ı tekrar kullanıma hazırla
        return nihaiRapor;
    }
}

// 5. Kullanım: Adım adım ve okunaklı yaratım
const builder = new RaporBuilder();

// Karmaşık Rapor (İsteğe bağlı adımlar atlanabilir/eklenebilir)
const raporB = builder
    .baslikEkle("Yıllık Analiz Raporu")
    .grafikEkle("Satış Hacimleri")
    .grafikEkle("Kullanıcı Artışı")
    .ozetEkle("Yıl sonu hedeflerine ulaşıldı.")
    .build();

raporB.goster(); 
// Çıktı: Başlık, Grafik ve Özet bölümleri sırayla yer alır.

                                  

Soyut Fabrika Deseni (Abstract Factory Pattern) Örnek Uygulama ve Detaylı Açıklama

Ürün Ailelerinin ve Kitlerin Yönetimi

Soyut Fabrika Deseni, birbiriyle ilişkili nesne ailelerini ( kitlerini ) veya birbirine bağımlı ürün gruplarını, bu ürünlerin >somut sınıflarını ( concrete classes ) belirtmek zorunda kalmadan oluşturmak için evrensel bir arayüz sağlar.

Bu desen, bir sistemin birden fazla olası konfigürasyon veya varyasyon altında çalışması gerektiğinde yani bir uygulamanın

"Koyu Tema" veya "Açık Tema" için farklı arayüz bileşenleri üretmesi kusursuz bir çözüm sunar.

Bu mimaride istemci kod, yalnızca kullanmak istediği Fabrika Ailesini seçer.

Geriye kalan tüm alt bileşenlerin ( Düğme, Pencere, Menü vb. ) seçilen aileye tam uyumlu olarak yaratılmasını bizzat Fabrika mekanizması garanti eder.

Felsefi Amaç: Ürün Ailelerinde Tutarlılık

Soyut Fabrika'nın temel varoluş amacı, sistem genelinde mimari tutarlılığı korumaktır , bu hedef iki ana sütun üzerine inşa edilmiştir:

1. Operasyonel Tutarlılık: Oluşturulan ürünlerin birbirleriyle görsel veya işlevsel olarak uyumlu olmasını sağlar.

Örneğin:

Bir "Koyu Tema Fabrikası" bir düğme üretiyorsa, sistem bunun mutlaka "Koyu Tema Düğmesi" olacağını bilir.

Böylece istemcinin yanlışlıkla "Açık Tema Penceresi" ile "Koyu Tema Düğmesi" bir arada kullanması gibi

mantıksal tasarım hataları imkansız hale getirilir.

2. Tam Yalıtım (Decoupling): İstemci kodunu, arka planda çalışan ürünlerin somut sınıflarından tamamen yalıtır.

İstemci yalnızca soyut fabrikalar ve soyut ürün arayüzleri ( interfaces ) ile etkileşim kurar.

Genişletilebilirlik ve Esneklik

Bu yalıtım sayesinde, sisteme yeni bir ürün ailesi ( yeni bir "Retro Tema" gibi ) eklemek istediğinizde, mevcut istemci kodunda herhangi bir değişiklik yapmanız gerekmez.

Sonuç olarak Soyut Fabrika, nesne üretimini bir üst seviyeye taşıyarak, sistemin karmaşık yapı taşlarını mantıksal gruplar halinde yöneten profesyonel bir mimari şemsiyedir.

Abstract Factory Method Pattern Soyut Fabrika Metodu Deseni Örneği

// 1. Soyut Ürünler Arayüzleri (Abstract Products)

// Soyut Ürün A: Düğme (Button)
class Dugme {
    render() { throw new Error("Uygulanmalı."); }
}

// Soyut Ürün B: Pencere (Window)
class Pencere {
    goster() { throw new Error("Uygulanmalı."); }
}

// 2. Somut Ürünler (Concrete Products) - Aile 1: Koyu Tema
class KoyuDugme extends Dugme {
    render() {
        console.log("[Koyu Tema] Koyu Renkli Düğme Render Edildi.");
    }
}
class KoyuPencere extends Pencere {
    goster() {
        console.log("[Koyu Tema] Koyu Renkli Pencere Gösteriliyor.");
    }
}

// 3. Somut Ürünler (Concrete Products) - Aile 2: Açık Tema
class AcikDugme extends Dugme {
    render() {
        console.log("[Açık Tema] Açık Renkli Düğme Render Edildi.");
    }
}
class AcikPencere extends Pencere {
    goster() {
        console.log("[Açık Tema] Açık Renkli Pencere Gösteriliyor.");
    }
}

// 4. Soyut Fabrika Arayüzü (Abstract Factory)
class ArayuzFabrikasi {
    dugmeYarat() { throw new Error("Uygulanmalı."); }
    pencereYarat() { throw new Error("Uygulanmalı."); }
}

// 5. Somut Fabrikalar (Concrete Factories)
class KoyuTemaFabrikasi extends ArayuzFabrikasi {
    dugmeYarat() {
        return new KoyuDugme();
    }
    pencereYarat() {
        return new KoyuPencere();
    }
}
class AcikTemaFabrikasi extends ArayuzFabrikasi {
    dugmeYarat() {
        return new AcikDugme();
    }
    pencereYarat() {
        return new AcikPencere();
    }
}

// 6. İstemci Kodu (Client Code) - Sadece Soyut Fabrika ile çalışır.
function uygulamaBaslat(fabrika) {
    // İstemci, somut sınıfları (KoyuDugme, AcikPencere vb.) bilmez.
    const dugme = fabrika.dugmeYarat();
    const pencere = fabrika.pencereYarat();

    dugme.render();
    pencere.goster();
}

console.log("--- Koyu Tema Modunda Uygulama ---");
uygulamaBaslat(new KoyuTemaFabrikasi());

console.log("\n--- Açık Tema Modunda Uygulama ---");
uygulamaBaslat(new AcikTemaFabrikasi());

/*
Çıktı:
--- Koyu Tema Modunda Uygulama ---
[Koyu Tema] Koyu Renkli Düğme Render Edildi.
[Koyu Tema] Koyu Renkli Pencere Gösteriliyor.

--- Açık Tema Modunda Uygulama ---
[Açık Tema] Açık Renkli Düğme Render Edildi.
[Açık Tema] Açık Renkli Pencere Gösteriliyor.
*/ 

Prototip Deseni (Prototype Pattern) Örnek Uygulama ve Detaylı Açıklama

Nesne Çoğaltma: Kopyalama Yoluyla Yaratım

Prototip Deseni, yeni nesneler oluşturmak için sıfırdan bir üretim yapmak yerine, mevcut bir nesneyi ( prototip ) temel alarak kopyalama ( cloning ) veya çoğaltma mekanizmasını kullanan stratejik bir Oluşturucu Desendir.

Bu desen, geleneksel new anahtar kelimesini kullanarak nesne oluşturma sürecine kıyasla, özellikle yüksek kaynak tüketimi gerektiren durumlarda çok daha ve esnek bir alternatif sunar.

Prototip sayesinde geliştirici, yaratılacak nesnelerin tam türlerini ( somut sınıflarını ) önceden bilmek zorunda kalmadan, mevcut örnekler üzerinden dinamik bir üretim hattı kurabilir.

Felsefi Amaç: Sınıf Tabanlıdan Örnek Tabanlıya Geçiş

Prototip deseninin temel vizyonu, nesne yaratımını katı "sınıf hiyerarşilerinden" kurtarıp, yaşayan "nesne örnekleri" üzerinden yürütmektir , bu vizyon iki ana avantaja dayanır:

1. Karmaşık Yaratımı Basitleştirme: Bir nesnenin sıfırdan yaratılması; karmaşık başlangıç değerleri ataması, dış servis bağlantıları veya ağır CPU hesaplamaları gerektiriyorsa, her new çağrısı sisteme büyük bir maliyet yükler.

Prototip, hali hazırda yapılandırılmış bir nesnenin bellek kopyasını alarak bu süreci milisaniyelere indirir.

2. Somut Sınıflardan Kaçınma: İstemci kodun, yaratmak istediği nesnelerin her bir somut sınıfına doğrudan bağımlı olma zorunluluğunu ortadan kaldırır.

İstemci sadece "kopyalanabilir" bir nesne talep eder.

Bu durum, sisteme yeni ürün tipleri eklendiğinde mevcut kodun bozulmamasını sağlayarak maksimum esneklik sunar.

Bellek Yönetimi ve Performans

JavaScript'in kendi doğası zaten Prototipsel Miras ( Prototypal Inheritance ) üzerine kurulu olduğu için, bu desen dille mükemmel bir uyum sergiler.

Sonuç olarak Prototip deseni, nesne üretimini bir "yeniden inşa" sürecinden çıkarıp "akıllı bir kopyalama" sürecine dönüştüren, sistem kaynaklarını koruyan ileri düzey bir optimizasyon mimarisidir.

Prototype Pattern Prototip Deseni Örneği

// 1. Prototip Arayüzü ve Temel Sınıf
// JavaScript'te genellikle base class olarak uygulanır.
class Karakter {
    constructor(ad, can) {
        this.ad = ad;
        this.can = can;
    }

    // Prototip Arayüzü: Klonlama metodu
    klonla() {
        // Yüzeysel Kopyalama (Shallow Copy) örneği
        return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
    }

    bilgiGoster() {
        console.log(`- Ad: ${this.ad}, Can: ${this.can}`);
    }
}

// 2. Somut Prototip 1: Savaşçı
class Savasci extends Karakter {
    constructor(ad, can, saldiri) {
        super(ad, can);
        this.saldiriGucu = saldiri;
    }

    klonla() {
        // Özelleştirilmiş kopyalama (gerekirse derin kopyalama burada yapılır)
        const klon = super.klonla();
        klon.ad = "Klonlanmış " + this.ad;
        return klon;
    }

    bilgiGoster() {
        super.bilgiGoster();
        console.log(`  > Saldırı Gücü: ${this.saldiriGucu}`);
    }
}

// 3. İstemci Kodu (Client Code)
console.log("--- PROTOTİP OLUŞTURMA ---");

// Başlangıç Prototipleri (Sistem bu hazır nesneleri tutar)
const temelSavasci = new Savasci("Gorok", 150, 25);
temelSavasci.bilgiGoster();

// 4. Yeni Nesneleri Klonlama Yoluyla Yaratma
console.log("\n--- KLONLAMA YOLUYLA YARATIM ---");

// a) Temel Savaşçıdan bir kopya yarat.
const savasciKlon1 = temelSavasci.klonla();
savasciKlon1.ad = "Yeni Birlik 1"; // Kopyalanan nesnenin özelliklerini değiştir.
savasciKlon1.bilgiGoster();

// b) Bir kopya daha yarat.
const savasciKlon2 = temelSavasci.klonla();
savasciKlon2.can = 50; // Kopyalanan nesnenin özelliğini değiştir.
savasciKlon2.bilgiGoster();

// Kontrol: Klonlar ve orijinal nesne birbirinden bağımsızdır (referanslar farklıdır)
console.log(`\nOrijinal ve Klon aynı nesne mi? ${temelSavasci === savasciKlon1}`); // Çıktı: false
*/

Yapısal Desenler (Structural Patterns) Genel Bilgi

Genel Bilgi: Karmaşık Yapıların Organizasyonu

Yapısal Desenler, mevcut sınıfların ve nesnelerin bir araya gelerek daha büyük, esnek ve verimli sistemler oluşturmasını sağlayan mimari organizasyon kurallarını içerir.

Bu desenlerin ana hedefi, bileşenler arasındaki ilişkileri düzenleyerek, sistemi gelecekteki yeni özelliklere karşı minimum eforla yönetilebilecek bir forma sokmaktır.

Yapısal desenlerin en ayırt edici özelliği, esneklik sağlamak için katı ve kırılgan olan kalıtım ( inheritance ) hiyerarşileri yerine, daha dinamik olan nesne bileşimini ( object composition ) temel almasıdır.

Temel Felsefe: Düzenleme ve Fonksiyonel Esneklik

Yapısal Desenler, sistemin parçalarını birbirine bağlarken ortaya çıkan karmaşıklığı soyutlamayı ve farklı bileşenler arasındaki uyumsuzlukları ortadan kaldırmayı amaçlar:

Arayüz Uyumsuzluğunu Giderme: Adapter deseni, birbirini tanımayan iki farklı yapıyı ortak bir köprü üzerinden bağlayarak entegrasyonu kolaylaştırır. ( eski bir kütüphane ile modern sisteminiz )

Karmaşıklığı Kapsülleme: Facade (Cephe) deseni, arka plandaki onlarca karmaşık süreci istemciden gizleyerek, dış dünyaya tek ve basit bir arayüz sunar, bu, kodun yeniden kullanılabilirliğini zirveye taşır.

Dinamik Yapılandırma ve Hiyerarşik Güç

Dinamik Fonksiyonellik: Decorator (Dekoratör) ve Bridge (Köprü) desenleri, nesneye yeni sorumluluklar ekleme yeteneğini kod yazım aşamasından çalışma zamanına ( runtime ) taşır. Bu sayede sistem, çalışma anında şekil değiştirebilir.

Hiyerarşik Temsil: Composite (Bileşik) deseni, tekil nesneler ile nesne grupları arasındaki farkı ortadan kaldırarak ağaç benzeri yapılar oluşturur.

İstemci, bir dosyayı mı yoksa koca bir klasörü mü yönettiğini bilmek zorunda kalmaz; her ikisine de aynı komutla hükmeder.

Sonuç olarak Yapısal Desenler, yazılımın parçalarını "Lego parçaları gibi" uyumlu hale getiren, sistemi hem sağlam hem de modüler kılan profesyonel bir mimari disiplindir.

Adapter Deseni (Adaptör Deseni) Örnek Uygulama ve Detaylı Açıklama

Mimari Köprü: Uyumsuz Arayüzlerin Senkronizasyonu

Adaptör Deseni, birbirini tanımayan ve normal şartlarda birlikte çalışması mümkün olmayan iki uyumsuz arayüzün ( interface ) sorunsuz bir şekilde etkileşime girmesini sağlayan stratejik bir köprü görevi görür.

Bu kavramı fiziksel dünyadaki bir elektrik adaptörüne benzetebiliriz: Farklı bir fiş tipine sahip olan bir cihazı ( Adaptee ), evinizdeki mevcut prize ( Target ) takmanızı sağlayan o küçük dönüştürücü, yazılım dünyasındaki Adaptör'ün tam karşılığıdır.

Felsefi Amaç: Uyumsuzluğu Yazılım Seviyesinde Çözmek

Adaptör deseninin temel varoluş felsefesi, sistemin mevcut iskeletini bozmadan dış dünyaya veya eski yapılara uyum sağlamaktır. Bu ihtiyaç genellikle iki senaryoda ortaya çıkar:

1. Dış Kaynak Entegrasyonu: Uygulamanızda kullanmak istediğiniz son derece güçlü bir kütüphane veya sınıf ( Adaptee ) vardır. Ancak bu kaynağın metot adları veya parametre yapıları, sizin sisteminizin beklediği standart arayüze ( Target ) uymamaktadır.

2. Yeniden Kullanım (Legacy Code): Güvenilirliği kanıtlanmış eski kodları ( Legacy ) çöpe atmak yerine, onları modern sisteminize entegre etmek istersiniz. Adaptör, bu eski bileşeni sarmalayarak ( wrap ) ona "yeni bir yüz" kazandırır.

Mühendislik Çözümü: Sarmalama ve Yönlendirme

Teknik Çözüm: Adaptör sınıfı, istemcinin ( client ) beklediği standart arayüzü uygular. İstemci, adaptöre bir çağrı yaptığında; adaptör bu çağrıyı yakalar, veriyi dönüştürür ve içeride sakladığı uyumsuz sınıfa ( Adaptee ) onun anlayacağı dilde iletir.

Bu sayede istemci, arka plandaki karmaşık dönüşüm süreçlerinden tamamen habersiz bir şekilde, tek tip bir arayüzle çalışmaya devam eder.

Sonuç olarak Adaptör, kodun esnekliğini artıran, sistemler arasındaki iletişim bariyerlerini yıkan ve mevcut yatırımları koruyan mühendislik odaklı bir tercümandır.

Adapter Deseni Adapter Deseni Örneği

// 1. Hedef (Target) Arayüz: İstemcinin beklediği arayüzü temsil eden sınıf.
class YeniGonderici {
    veriGonder(veri) {
        throw new Error("Bu metot uygulanmalıdır.");
    }
}

// 2. Uyumsuz Sınıf (Adaptee): Değiştiremeyeceğimiz eski kütüphane.
class EskiSistem {
    eskiVeriYolla(payload) {
        console.log(`[ESKİ SİSTEM] Payload alindi ve yollandi: ${payload}`);
        return true;
    }
}

// 3. Adaptör (Adapter): İki arayüzü birbirine bağlar.
class EskiSistemAdaptoru extends YeniGonderici {
    constructor(adaptee) {
        // Uyumsuz sınıfın bir referansını tutar (Nesne Bileşimi).
        super();
        this.adaptee = adaptee; 
    }

    // Hedef arayüzünü uygular.
    veriGonder(veri) {
        console.log(`[ADAPTÖR] Yeni formatı, eski sisteme dönüştürüyor...`);
        
        // 🚨 Dönüşüm: Yeni formatı (veri), eski metodun (eskiVeriYolla) beklediği
        // parametreye (payload) ve metoda çevirir.
        const payload = `VERI_PAKETI:${veri}`;
        this.adaptee.eskiVeriYolla(payload);
    }
}

// 4. İstemci Kodu (Client Code)

// İstemci, sadece YeniGonderici arayüzü ile çalışmayı bekler.
function istemciIslemi(gonderici) {
    gonderici.veriGonder("Islem verisi: 12345");
}

// Orijinal Uyumsuz Sınıf
const eskiSistem = new EskiSistem();

// Adaptör oluşturulur ve uyumsuz sistem ile sarmalanır.
const adapter = new EskiSistemAdaptoru(eskiSistem);

// İstemci kodu, adaptör sayesinde uyumsuz sistemi sorunsuz kullanabilir.
istemciIslemi(adapter);

// Çıktı:
// [ADAPTÖR] Yeni formatı, eski sisteme dönüştürüyor...
// [ESKİ SİSTEM] Payload alindi ve yollandi: VERI_PAKETI:Islem verisi: 12345
          
                                            

Köprü Deseni (Bridge Pattern) Örnek Uygulama ve Detaylı Açıklama

Mimari Ayrışma: Soyutlama ve Uygulama Arasındaki Köprü

Köprü Deseni, yüksek seviyeli bir mantığı ( Abstraction / Soyutlama ) bu mantığın teknik detaylarından

( Implementation / Uygulama ) fiziksel olarak ayırarak, her ikisinin de birbirini etkilemeden, bağımsız bir şekilde evrimleşmesini sağlayan yapısal bir mimaridir.

Bu ayrım, soyutlama ve uygulamanın birbirine sıkı sıkıya bağlı ( tightly coupled ) olmamasını sağlamak adına aralarında esnek bir "köprü" kurar.

Desenin temel misyonu, yazılım projelerinde korkulu bir rüya olan "Sınıf Patlaması" ( Class Explosion ) sorununa matematiksel bir çözüm getirmektir.

Eğer bir hiyerarşide hem nesnenin türü ( biçim ) hem de çalışma platformu ( teknik altyapı ) değişebiliyorsa, bu iki farklı boyutu yönetmek için en ideal yol Köprü Deseni’dir.

Felsefi Amaç: Bileşimin Kalıtıma Karşı Zaferi

Köprü deseninin çekirdek felsefesi, modern yazılımın altın kuralı olan "Bileşimi Kalıtıma Tercih Etmek"

( Composition over Inheritance ) ilkesini en uç noktada uygulamaktır.

Sınıf Patlamasını Önleme: Diyelim ki elimizde 3 farklı şekil ( Kare, Üçgen, Daire ) ve 3 farklı çizim teknolojisi ( OpenGL, DirectX, WebGL ) var. Geleneksel kalıtımı kullanırsanız, her kombinasyon için ayrı sınıf açmanız gerekir ( 3x3=9 somut sınıf ).

Köprü Deseni ise bu boyutları ayırarak sadece 3+3=6 sınıf ile tüm kombinasyonları yönetmenizi sağlar.

Mühendislik Esnekliği ve Bağımsız Gelişim

Tam Esneklik: Bu mimari sayesinde teknik uygulama ( çizim mantığı ), soyutlamadan ( şekil tipi ) tamamen bağımsız hale gelir.

Yani, mevcut şekillerin koduna dokunmadan sisteme yeni bir çizim teknolojisi ( örneğin Vulkan API ) ekleyebilir veya mevcut teknolojileri güncelleyebilirsiniz.

Sonuç olarak Köprü Deseni, karmaşık hiyerarşileri basitleştiren, sistemin bakımını kolaylaştıran ve farklı teknolojik katmanlar arasında "akıllı bir izolasyon" sağlayan üst düzey bir mühendislik standardıdır.

Bridge Pattern Köprü Deseni Örneği

// 1. Uygulama (Implementor) Arayüzü: Alt seviye işlemleri tanımlar (Ekran Büyüklüğü)
class EkranBoyutu {
    mesajGoster(mesaj) {
        throw new Error("Uygulanmalı.");
    }
}

// 2. Somut Uygulamalar (Concrete Implementors)
class GenisEkran extends EkranBoyutu {
    mesajGoster(mesaj) {
        console.log(`[GENİŞ EKRAN UYGULAMASI] ${mesaj} (Çok Detaylı)`);
    }
}

class DarEkran extends EkranBoyutu {
    mesajGoster(mesaj) {
        console.warn(`[DAR EKRAN UYGULAMASI] ${mesaj} (Kısa)`);
    }
}

// 3. Soyutlama (Abstraction) Sınıfı: Uygulamaya referans tutar (Cihaz Tipi)
class Cihaz {
    constructor(ekranBoyutu) {
        // 💡 Köprü: Uygulama (EkranBoyutu) referansını tutar.
        this.implementor = ekranBoyutu; 
    }

    uyariGoster(mesaj) {
        // Soyutlama, implementor'a delege eder.
        this.implementor.mesajGoster(mesaj);
    }
}

// 4. Gelişmiş Soyutlamalar (Refined Abstractions)
class MasaustuCihaz extends Cihaz {
    uyariGoster(mesaj) {
        const masaustuMesaj = `Masaüstü Bildirimi: ${mesaj}`;
        this.implementor.mesajGoster(masaustuMesaj);
    }
}

class MobilCihaz extends Cihaz {
    uyariGoster(mesaj) {
        const mobilMesaj = `Mobil Uyarı (Batarya Durumu): ${mesaj}`;
        this.implementor.mesajGoster(mobilMesaj);
    }
}

// 5. İstemci Kodu (Client Code)

// A: Mobil Cihaz, Geniş Ekran modunda çalışıyor.
const mobilGeniş = new MobilCihaz(new GenisEkran());
mobilGeniş.uyariGoster("Yeni uygulama sürümü mevcut.");

// B: Masaüstü Cihaz, Dar Ekran modunda çalışıyor.
const masaustuDar = new MasaustuCihaz(new DarEkran());
masaustuDar.uyariGoster("Veritabanı bağlantısı kesildi.");

/*
Çıktı:
[GENİŞ EKRAN UYGULAMASI] Mobil Uyarı (Batarya Durumu): Yeni uygulama sürümü mevcut. (Çok Detaylı)
[DAR EKRAN UYGULAMASI] Masaüstü Bildirimi: Veritabanı bağlantısı kesildi. (Kısa)

Görüldüğü gibi, aynı Cihaz tipi (Örn: MobilCihaz), farklı bir EkranBoyutu (Uygulama) ile birleştirilerek bağımsız olarak değiştirilebilir.
*/

Bileşik Deseni (Composite Pattern) Örnek Uygulama ve Detaylı Açıklama

Hiyerarşik Bütünlük: Parça-Bütün İlişkilerinin Yönetimi

Bileşik Deseni, nesneleri ağaç benzeri ( tree-like ) hiyerarşiler halinde gruplandırmak amacıyla kullanılır. Bu sayede istemci, tek bir nesne ile bu nesnelerden oluşan devasa grupları ( bileşikleri ) birbirinden ayırt etmeksizin aynı şekilde ele alabilir.

Desenin temel felsefesi, parça-bütün ( part-whole ) ilişkilerini temsil ederek sistemdeki nesne karmaşıklığını tek bir standart altında toplamaktır.

Şeffaf Erişim: Bileşik deseni, istemcinin ( client ) bir nesnenin atomik bir birim ( Yaprak / Leaf ) mi yoksa dallanıp budaklanan bir kapsayıcı ( Bileşik / Composite ) mı olduğunu bilme zorunluluğunu ortadan kaldırır. İstemci sadece ortak bir Component arayüzü ile konuşur.

Felsefi Amaç: Tekil ve Gruplanmış Yapıları Birleştirmek

Bileşik deseninin temel vizyonu, hiyerarşik ilişkileri soyutlayarak kodun bakımını ve kullanımını basitleştirmektir:

Tek Tip İşlem: İstemci kodunu dallanıp budaklanan if/else bloklarından kurtarır. Örneğin, bir dosya sisteminde tek bir dosya ile koca bir klasörün boyutunu hesaplamak istediğinizde, her ikisi için de sadece boyutAl() metodunu çağırmanız yeterlidir. Sistemin geri kalanı aradaki yapısal farkla ilgilenmez.

Mühendislik Gücü: Doğal Hiyerarşi ve Özyineleme

Hiyerarşik Yapı: Organizasyon şemaları, dosya dizinleri veya HTML DOM gibi ağaç yapılarını temsil etmek için en doğal mimariyi sunar.

Özyinelemeli (Recursive) İşlem Kolaylığı: Bileşik nesneler, kendi içlerinde hem yaprakları hem de diğer bileşikleri barındırabilir. Bu öz-benzerlik ( self-similarity ), karmaşık hiyerarşiler üzerinde yapılacak işlemleri tek bir tetiklemeyle tüm alt dallara yaymayı mümkün kılar.

Sonuç olarak Bileşik deseni, sistemdeki nesne organizasyonunu basitleştiren, istemci tarafındaki mantıksal yükü azaltan ve "bir bütünü parçalarıyla aynı dilden konuşmaya zorlayan" profesyonel bir yapısal disiplindir.

Composite Pattern Bileşik Deseni Örneği

// 1. Bileşen (Component) Arayüzü (Temel Sınıf)
class PersonelBileseni {
    constructor(ad, maliyet) {
        this.ad = ad;
        this.maliyet = maliyet || 0;
    }

    // Ortak İşlem
    maliyetAl() {
        return this.maliyet;
    }

    // Çocuk Yönetimi (Composite için varsayılan boş metotlar)
    cocukEkle(bilesen) { } 
    cocuklariGoster() { }
}

// 2. Yaprak (Leaf): Tekil çalışanlar
class Calisan extends PersonelBileseni {
    // Yaprak, çocuk yönetimi metotlarını uygulamasına gerek duymaz.
    constructor(ad, maas) {
        super(ad, maas);
    }
    
    maliyetAl() {
        console.log(`[Tekil Çalışan] ${this.ad} - Maaş: ${this.maliyet} TL`);
        return this.maliyet;
    }
}

// 3. Bileşik (Composite): Çalışan grupları veya bölümler
class Departman extends PersonelBileseni {
    constructor(ad) {
        super(ad);
        this.cocuklar = [];
    }

    cocukEkle(bilesen) {
        this.cocuklar.push(bilesen);
    }

    // 💡 Özyinelemeli İşlem: Kendi maliyeti, çocuklarının maliyetleri toplamıdır.
    maliyetAl() {
        let toplam = 0;
        console.log(`\n--- DEPARTMAN: ${this.ad} Maliyet Hesaplama ---`);
        this.cocuklar.forEach(cocuk => {
            // Özyinelemeli çağrı: Çocuk Yaprak mı (Çalışan) yoksa Bileşik mi (Başka Departman) 
            // olduğunu bilmeden ortak metodu çağırır.
            toplam += cocuk.maliyetAl(); 
        });
        this.maliyet = toplam;
        console.log(`--- ${this.ad} Toplam Maliyet: ${this.maliyet} TL ---`);
        return this.maliyet;
    }
}

// 4. İstemci Kodu (Client Code)

// Yaprakları Yaratma
const yazilimci1 = new Calisan("Ahmet (Backend)", 80000);
const yazilimci2 = new Calisan("Ayşe (Frontend)", 70000);
const stajyer = new Calisan("Can (Stajyer)", 10000);

// Bileşikleri Yaratma
const yazilimDepartmani = new Departman("Yazılım Geliştirme");
yazilimDepartmani.cocukEkle(yazilimci1);
yazilimDepartmani.cocukEkle(yazilimci2);

const stajyerDepartmani = new Departman("Yeni Yetenekler");
stajyerDepartmani.cocukEkle(stajyer);

// Daha Büyük Bir Bileşik Yaratma (Hiyerarşi)
const tumSirket = new Departman("Global Şirket");
tumSirket.cocukEkle(yazilimDepartmani); // Başka bir Bileşik eklendi
tumSirket.cocukEkle(stajyerDepartmani); // Başka bir Bileşik eklendi

// İstemci, en üst Bileşik (tumSirket) üzerinde tek bir metot çağırır.
tumSirket.maliyetAl();

/*
Çıktı:
--- DEPARTMAN: Global Şirket Maliyet Hesaplama ---

--- DEPARTMAN: Yazılım Geliştirme Maliyet Hesaplama ---
[Tekil Çalışan] Ahmet (Backend) - Maaş: 80000 TL
[Tekil Çalışan] Ayşe (Frontend) - Maaş: 70000 TL
--- Yazılım Geliştirme Toplam Maliyet: 150000 TL ---

--- DEPARTMAN: Yeni Yetenekler Maliyet Hesaplama ---
[Tekil Çalışan] Can (Stajyer) - Maaş: 10000 TL
--- Yeni Yetenekler Toplam Maliyet: 10000 TL ---

--- Global Şirket Toplam Maliyet: 160000 TL ---
*/
        */

Dekoratör Deseni (Decorator Pattern) Örnek Uygulama ve Detaylı Açıklama

Dinamik Fonksiyonellik: Nesneleri Katmanlarla Zenginleştirme

Dekoratör Deseni, bir nesneye uygulama çalışırken ( runtime ) temel yapısını bozmadan ek işlevsellik veya yeni sorumluluklar yüklemek için kullanılır.

Bu desen, nesnenin ana arayüzünü sabit tutarken ona yeni yetenekler kazandırır ve katı kalıtım ( inheritance ) hiyerarşilerine karşı son derece esnek bir alternatif sunar.

Sarmalama Mantığı: Günlük hayattan bir örnekle; sade bir kahveye ( temel nesne ) süt, şurup veya krema eklemeniz, o kahveyi "dekore etmeniz" demektir. Her bir ekstra, kahvenin temel kimliğini (içecek olması) değiştirmez, ancak ona yeni bir özellik (tat/maliyet) katar. Bu katmanlar, bir soğan zarı gibi iç içe geçerek sınırsız kombinasyonda zincirlenebilir.

Felsefi Amaç: Kalıtımın Sınırlarını Esneklikle Aşmak

Dekoratör deseninin özü, Tek Sorumluluk Prensibi ( SRP ) çerçevesinde kalarak, nesneleri devasa ve karmaşık sınıflara dönüştürmeden özelleştirmektir:

Sınıf Patlamasını (Class Explosion) Önleme: Diyelim ki bir nesnenin 10 farklı opsiyonel özelliği var. Sadece kalıtım kullanarak her özelliği ve bunların kombinasyonlarını modellemeye kalkarsanız, matematiksel olarak yüzlerce ( 2 üzeri 10 ) farklı alt sınıf yaratmanız gerekir. Dekoratör ise sadece 1 temel sınıf ve 10 küçük dekoratör sınıfıyla bu devasa kombinasyon havuzunu dinamik olarak yönetmenizi sağlar.

Mühendislik Avantajı: Çalışma Zamanı Genişletme

Dinamik Genişletme: Geleneksel yöntemlerde nesne davranışı "derleme zamanında" ( compile time ) taşlaşır. Dekoratör ise bu kararı uygulama çalışırken vermenize olanak tanır. Bir nesne bir kez yaratıldıktan sonra bile, ihtiyaca göre yeni "kabuklarla" ( dekoratörlerle ) sarmalanabilir.

Şeffaf Arayüz Koruma: Dekoratörler, sarmaladıkları temel bileşenle tamamen aynı arayüze ( interface ) sahiptir. Bu sayede istemci ( client ) kodu, elindeki nesnenin saf haliyle mi yoksa 5 katmanlı dekore edilmiş haliyle mi çalıştığını fark etmez; her ikisine de aynı standart metodla hükmeder.

Sonuç olarak Dekoratör, yazılımda "açık/kapalı prensibini" ( Open/Closed Principle ) en zarif şekilde uygulayan, sistemi modüler ve hafif tutan ileri düzey bir yapısal mimaridir.

Decorator Pattern Dekoratör Deseni Örneği

// 1. Bileşen (Component) Arayüzü
class Kahve {
    maliyetAl() { throw new Error("Uygulanmalı."); }
    aciklamaAl() { throw new Error("Uygulanmalı."); }
}

// 2. Somut Bileşen (Concrete Component): Temel Ürün
class SadeKahve extends Kahve {
    maliyetAl() {
        return 10;
    }
    aciklamaAl() {
        return "Sade Kahve";
    }
}

// 3. Temel Dekoratör (Base Decorator)
class KahveDekoratoru extends Kahve {
    constructor(kahve) {
        super();
        // 💡 Sarmalanan nesneye referans
        this.sarmalanan = kahve; 
    }

    maliyetAl() {
        // Çağrıyı delege etme
        return this.sarmalanan.maliyetAl(); 
    }
    aciklamaAl() {
        // Çağrıyı delege etme
        return this.sarmalanan.aciklamaAl();
    }
}

// 4. Somut Dekoratörler (Concrete Decorators)
class Sut extends KahveDekoratoru {
    maliyetAl() {
        // Temel maliyete ek ücret ekle
        return super.maliyetAl() + 5; 
    }
    aciklamaAl() {
        // Temel açıklamaya kendi özelliğini ekle
        return `${super.aciklamaAl()}, Sütlü`;
    }
}

class Şurup extends KahveDekoratoru {
    maliyetAl() {
        return super.maliyetAl() + 8; 
    }
    aciklamaAl() {
        return `${super.aciklamaAl()}, Şuruplu`;
    }
}

// 5. İstemci Kodu (Client Code)

// Başlangıç: Temel Sade Kahve
let kahve = new SadeKahve();
console.log(`1. Sipariş: ${kahve.aciklamaAl()} - ${kahve.maliyetAl()} TL`); 

// 💡 Dinamik Dekorasyon: Çalışma zamanında yeni özellikler ekleme

// 2. Sipariş: Sade Kahve + Süt
kahve = new Sut(kahve);
console.log(`2. Sipariş: ${kahve.aciklamaAl()} - ${kahve.maliyetAl()} TL`); // (10 + 5) = 15 TL

// 3. Sipariş: Sade Kahve + Süt + Şurup (Zincirleme)
kahve = new Şurup(kahve);
console.log(`3. Sipariş: ${kahve.aciklamaAl()} - ${kahve.maliyetAl()} TL`); // (10 + 5 + 8) = 23 TL

/*
Çıktı:
1. Sipariş: Sade Kahve - 10 TL
2. Sipariş: Sade Kahve, Sütlü - 15 TL
3. Sipariş: Sade Kahve, Sütlü, Şuruplu - 23 TL
*/

Cephe Deseni (Facade Pattern) Örnek Uygulama ve Detaylı Açıklama

Karmaşıklığı Gizleme: Tek ve Basit Bir Arayüz

Cephe Deseni, bir alt sistemin içinde barınan karmaşık ve çok sayıdaki sınıf kümesini, dış dünyaya karşı tek ve son derece basitleştirilmiş bir arayüz arkasına gizleme sanatıdır.

Mimari Bir Kapı: Cephe ( Facade ), istemcinin karmaşık sistem fonksiyonlarına erişmesi için tek bir giriş noktası görevi görür. İstemci, bir işlemi gerçekleştirmek için arka planda çalışan 10-15 farklı sınıfı koordine etmekle vakit kaybetmez; sadece Cephe'nin sunduğu o "sihirli" butona basar.

Bu yaklaşım, sadece geliştirme sürecini hızlandırmakla kalmaz, aynı zamanda istemci kodu ile alt sistemin iç bileşenleri arasındaki sıkı bağlılığı (tight coupling) tamamen ortadan kaldırır.

Felsefi Amaç: Karmaşıklığı Yalıtmak ve Yönetmek

Cephe deseninin temel varoluş amacı, kaosu düzene sokmak ve devasa sistemleri daha yönetilebilir parçalara bölmektir:

Bütünsel Basitleştirme: İstemci tarafında, bir görevi tamamlamak için alt sistemdeki parçaları doğru sırayla başlatma, yapılandırma ve yönetme yükünü kaldırır. Cephe, bu karmaşık koordine etme mantığını kendi içine kapsüller (encapsulate).

Gevşek Bağlılık (Decoupling): Alt sistemin derinliklerindeki bir sınıf değiştiğinde veya yeni bir yapı eklendiğinde istemci kodu bundan asla etkilenmez. Çünkü istemci, sistemin iç detaylarına değil, sadece sarsılmaz bir kale gibi duran Cephe arayüzüne bağımlıdır.

Modülerlik ve Okunabilirlik Stratejisi

Stratejik Giriş Noktası: Alt sisteme erişimi organize eden mantıklı bir başlangıç noktası sunarak, projenin okunabilirliğini ve modüler yapısını en üst düzeye çıkarır.

Sonuç olarak Cephe deseni, yazılım mimarisinde "detaylarda boğulmadan iş bitirme" felsefesini temsil eden, sistemin karmaşık iç motorunu şık bir kaporta ile örten profesyonel bir düzenleyicidir.

Facade Pattern Cephe Deseni Örneği

// 1. Alt Sistem Sınıfları (Karmaşık Bileşenler)

class CPU {
    bootAddress() {
        console.log("-> CPU: Boot adresi okunuyor.");
    }
}

class RAM {
    load(adres, veri) {
        console.log(`-> RAM: Veri ${veri} adrese ${adres} yükleniyor.`);
    }
}

class HDD {
    read(baslangic) {
        console.log(`-> HDD: ${baslangic}'dan boot sektör verisi okunuyor.`);
        return "OS Verisi";
    }
}

// 2. Cephe (Facade): Tüm alt sistem koordinasyonunu kapsüller.
class BilgisayarCephesi {
    constructor() {
        // Alt sistem bileşenlerine referans tutar.
        this.cpu = new CPU();
        this.ram = new RAM();
        this.hdd = new HDD();
    }

    // 💡 Basitleştirilmiş Arayüz: İstemci sadece bu metodu çağırır.
    baslat() {
        console.log("--- Bilgisayar Başlatma İşlemi Başlıyor ---");
        
        // Karmaşık alt sistem koordinasyon sırası:
        this.cpu.bootAddress();
        const bootVerisi = this.hdd.read(0);
        this.ram.load("0x0001", bootVerisi);
        console.log("--- Bilgisayar Başarıyla Başlatıldı ---");
    }

    // İstemcinin kullanabileceği diğer basitleştirilmiş metotlar...
}

// 3. İstemci Kodu (Client Code)

// İstemci, 3 alt sistemi koordine etmek zorunda kalmaz.
const bilgisayar = new BilgisayarCephesi();

// İstemci, tüm karmaşıklığı kapsülleyen tek bir metodu çağırır.
bilgisayar.baslat();

/*
Çıktı:
--- Bilgisayar Başlatma İşlemi Başlıyor ---
-> CPU: Boot adresi okunuyor.
-> HDD: 0'dan boot sektör verisi okunuyor.
-> RAM: Veri OS Verisi adrese 0x0001 yükleniyor.
--- Bilgisayar Başarıyla Başlatıldı ---
*/
                

Vekil Deseni (Proxy Pattern) Örnek Uygulama ve Detaylı Açıklama

Erişim Denetimi: Yer Tutucu ve Aracı Gücü

Vekil Deseni, başka bir nesneye erişimi doğrudan sağlamak yerine, o nesnenin önünde bir yer tutucu ( placeholder ) veya temsilci olarak konumlanan yapısal bir desendir.

Şeffaf Vekalet: Vekil nesnesi, orijinal nesneyle tamamen aynı arayüze sahiptir. Bu sayede istemci ( client ), gerçek nesneyle mi yoksa onun vekiliyle mi konuştuğunu anlamaz; aradaki fark tamamen gizlenir.

Vekil, istemciden gelen tüm çağrıları bir "gardiyan" gibi yakalar. Bu çağrıları ya olduğu gibi orijinal nesneye iletir ya da iletmeden önce/sonra kritik ek mantıklar ( güvenlik kontrolü, önbellekleme, gecikmeli yükleme ) işleterek süreci yönetir.

Felsefi Amaç: Kontrollü Erişim ve Akıllı Genişletme

Vekil deseninin temel amacı, nesneye doğrudan dokunmanın riskli veya maliyetli olduğu durumlarda "akıllı bir tampon" oluşturmaktır:

1. Erişim Kontrolü (Koruma Vekili): Hassas bir nesneye erişimi kullanıcının yetki seviyesine göre kısıtlar. Örneğin; bir admin verileri hem okuyup hem yazabilirken, standart bir kullanıcının yazma metodunu çağırması Proxy seviyesinde engellenir.

2. Gecikmeli Yükleme (Sanal Vekil): Orijinal nesnenin yaratılması bellek veya işlemci açısından maliyetliyse ( örneğin devasa bir görüntü dosyası veya kompleks bir DB bağlantısı ), Proxy nesneyi hemen oluşturmaz. Nesne gerçekten kullanılana kadar bu süreci erteler ( lazy loading ).

3. Önbellekleme (Cache Proxy): Sürekli aynı sonucu üreten pahalı ve yavaş operasyonların sonuçlarını Proxy üzerinde saklar. Yeni bir istek geldiğinde, Proxy gerçek nesneye gitmeden önce önbelleği kontrol ederek performans dopingi sağlar.

Mühendislik Katmanı: Nesne Davranışını Yönetmek

Sonuç olarak Vekil deseni, sistemin ana iş mantığını bozmadan ona güvenlik ve hız katmanları ekleyen, "doğrudan erişim" kaosunu "kontrollü vekalet" düzenine çeviren profesyonel bir mimari araçtır.

Proxy Pattern Vekil (Proxy) Deseni Örneği

// 1. Arayüz (Subject)
class KullaniciServisi {
    kullanicilariAl() {
        throw new Error("Uygulanmalı.");
    }
}

// 2. Orijinal Nesne (Real Subject): Gerçek, yavaş veritabanı erişimi
class GercekKullaniciServisi extends KullaniciServisi {
    kullanicilariAl() {
        // 💡 Gerçekçi bir gecikme ekleyelim (Sanki DB'den çekiyor)
        console.log("-> DB: Kullanıcı verileri veritabanından YÜKLENİYOR...");
        return [
            { id: 1, ad: "Ali" }, 
            { id: 2, ad: "Veli" }
        ];
    }
}

// 3. Vekil (Proxy): Erişimi kontrol eder ve önbellekleme yapar.
class KullaniciServisiVekili extends KullaniciServisi {
    constructor(kullaniciYetkisi) {
        super();
        this.gercekServis = new GercekKullaniciServisi();
        this.onbellek = null; // Önbellek depolama alanı
        this.yetki = kullaniciYetkisi;
    }

    kullanicilariAl() {
        // Kontrol 1: Yetkilendirme Kontrolü (Koruma Vekili)
        if (this.yetki !== "Admin") {
            console.error("❌ Hata: Bu işleme erişim yetkiniz (Admin) yoktur.");
            return [];
        }

        // Kontrol 2: Önbellekleme Kontrolü (Önbellek Vekili)
        if (this.onbellek) {
            console.log("-> PROXY: Kullanıcı verileri önbellekten getirildi.");
            return this.onbellek;
        }

        // Yetki varsa ve önbellek yoksa, orijinal nesneyi çağır.
        const veriler = this.gercekServis.kullanicilariAl();
        this.onbellek = veriler; // Önbelleğe kaydet.
        return veriler;
    }
}

// 4. İstemci Kodu (Client Code)

// 1. Senaryo: Admin kullanıcısı (Yetkili Erişim + Önbellekleme Testi)
console.log("--- 1. İstemci: Yönetici (Admin) ---");
const adminVekil = new KullaniciServisiVekili("Admin");

// İlk çağrı: DB'den yüklenir ve önbelleğe alınır.
let adminVeri1 = adminVekil.kullanicilariAl();
console.log(`Admin sonuç 1: ${adminVeri1.length} kullanıcı.`);

// İkinci çağrı: Önbellekten getirilir.
let adminVeri2 = adminVekil.kullanicilariAl();
console.log(`Admin sonuç 2: ${adminVeri2.length} kullanıcı (Tekrar çağrılmadı).`);


// 2. Senaryo: Misafir kullanıcısı (Yetkisiz Erişim)
console.log("\n--- 2. İstemci: Misafir (Guest) ---");
const misafirVekil = new KullaniciServisiVekili("Guest");

// Misafir çağrısı: Yetki nedeniyle engellenir.
misafirVekil.kullanicilariAl();

/*
Çıktı:
--- 1. İstemci: Yönetici (Admin) ---
-> DB: Kullanıcı verileri veritabanından YÜKLENİYOR...
Admin sonuç 1: 2 kullanıcı.
-> PROXY: Kullanıcı verileri önbellekten getirildi.
Admin sonuç 2: 2 kullanıcı (Tekrar çağrılmadı).

--- 2. İstemci: Misafir (Guest) ---
❌ Hata: Bu işleme erişim yetkiniz (Admin) yoktur.
*/

Sinek Sıklet Deseni (Flyweight Pattern) Örnek Uygulama ve Detaylı Açıklama

Bellek Verimliliği: Paylaşılan Hafif Nesneler

Sinek Sıklet Deseni, sistemde çok sayıda benzer nesnenin bulunduğu durumlarda, bu nesnelerin ortak özelliklerini paylaşarak bellek (RAM) tüketimini dramatik şekilde azaltan bir yapısal desendir.

Bu desen, nesnelerin sahip olduğu verileri (durumları) iki temel kategoriye ayırarak bir "akıllı depolama" mantığı kurar:

1. İçsel Durum (Intrinsic State): Nesneler arasında tamamen aynı olan ve değişmeyen verilerdir ( örneğin; bir ormandaki binlerce çam ağacının ortak yaprak dokusu veya rengi ). Bu veriler Sinek Sıklet nesnesinin kalbinde bir kez depolanır ve tüm sistem tarafından ortaklaşa kullanılır.

2. Dışsal Durum (Extrinsic State): Her nesneye özgü olan ve bağlama göre değişen verilerdir ( ağacın haritadaki koordinatları veya o anki büyüklüğü ). Bu veriler nesnenin içinde tutulmaz; bunun yerine işlem anında dışarıdan ( istemci kodundan ) parametre olarak iletilir.

Felsefi Amaç: Büyük Ölçekli Sistemlerde Optimizasyon

Sinek Sıklet deseninin temel felsefesi, "veri tekrarını" matematiksel bir disiplinle engelleyerek uygulamanın ölçeklenebilirliğini artırmaktır:

Kaynak Tasarrufu: Birbirinin kopyası olan binlerce bağımsız nesne yaratıp belleği şişirmek yerine, bu nesnelerin "ruhunu" (ortak verisini) tek bir merkezde toplar. İstemciler bu merkezi nesneyi paylaşarak sistemi hafifletir.

Verimli Ölçekleme: Bir oyun haritasındaki 100.000 ağacı veya bir metin düzenleyicideki 50.000 karakteri, bellek sınırlarını aşmadan yönetebilmenin yegane yolu budur. Sistem, nesne sayısı arttıkça çökmez; aksine ortak veriyi kullanarak akıcılığını korur.

Mühendislik Çıkarımı: Hafiflik ve Performans

Sonuç olarak Sinek Sıklet deseni, yazılımda "az veriyle çok iş yapma" sanatıdır. Bellek yönetimini bir mimari avantaja dönüştürerek, donanım kaynaklarını en verimli şekilde kullanan yüksek performanslı sistemler inşa edilmesini sağlar.

Flyweight Pattern Sinek Sıklet Deseni Örneği

// 1. Sinek Sıklet (Flyweight) Sınıfı: Paylaşılan Veri (Ağaç Tipi)
class AgacTipi {
    constructor(ad, renk, doku) {
        // 💡 İçsel Durum: Paylaşılır ve sabittir.
        this.ad = ad;
        this.renk = renk;
        this.doku = doku;
    }

    // Dışsal durum parametre olarak alınır.
    ciz(x, y) {
        console.log(`Ağaç çizildi: ${this.ad} (${this.renk}, ${this.doku}) konum: (${x}, ${y})`);
    }
}

// 2. Sinek Sıklet Fabrikası (Flyweight Factory)
class AgacTipiFabrikasi {
    constructor() {
        this.agacTipleri = {}; // Havuz (Pool)
        this.sayac = 0;
    }

    getAgacTipi(ad, renk, doku) {
        const anahtar = `${ad}_${renk}_${doku}`; // Eşsiz anahtar

        // Kontrol: Nesne havuzda var mı?
        if (!this.agacTipleri[anahtar]) {
            console.log(`[FABRİKA] Yeni Sinek Sıklet Yaratılıyor: ${ad}`);
            this.agacTipleri[anahtar] = new AgacTipi(ad, renk, doku);
            this.sayac++;
        }
        
        // Mevcut veya yeni yaratılan nesneyi döndür.
        return this.agacTipleri[anahtar];
    }
}

// 3. İstemci (Client): Dışsal Durumu tutar (Ağaçlar)
class Agac {
    constructor(x, y, agacTipi) {
        // 💡 Dışsal Durum: Her ağaca özgü, paylaşılamaz.
        this.x = x;
        this.y = y;
        // İçsel Durum: Sinek Sıklet nesnesine referans.
        this.agacTipi = agacTipi; 
    }

    ciz() {
        // Dışsal durumu, paylaşılan Sinek Sıklet metoduna ilet.
        this.agacTipi.ciz(this.x, this.y);
    }
}

// Kullanım: Çok sayıda ağaç yaratma

const fabrika = new AgacTipiFabrikasi();
const orman = [];
const toplamAgacSayisi = 10000;

for (let i = 0; i < toplamAgacSayisi; i++) {
    const tip = (i % 2 === 0) ? 'Çam' : 'Meşe'; // İki tip ağacımız var
    const renk = (tip === 'Çam') ? 'Koyu Yeşil' : 'Kahverengi';
    const doku = (tip === 'Çam') ? 'İğneli' : 'Geniş Yapraklı';

    // 💡 Sadece 2 adet Sinek Sıklet nesnesi yaratılacak (Çam ve Meşe)
    const agacTipi = fabrika.getAgacTipi(tip, renk, doku);

    // Her ağaç, kendine özgü bir dışsal durumla (konum) yaratılır.
    const yeniAgac = new Agac(i * 10, i * 20, agacTipi);
    orman.push(yeniAgac);
}

// Kontrol: Ormanda 10.000 ağaç nesnesi var, ama sadece 2 adet AgacTipi (Sinek Sıklet) nesnesi yaratıldı.
console.log(`\nToplam Yaratılan Ağaç Nesnesi (Client): ${orman.length}`);
console.log(`Toplam Yaratılan Sinek Sıklet (Paylaşılan): ${fabrika.sayac}`);

/*
Çıktı (Örnek Kısa Versiyonu):
[FABRİKA] Yeni Sinek Sıklet Yaratılıyor: Çam
[FABRİKA] Yeni Sinek Sıklet Yaratılıyor: Meşe
...
Toplam Yaratılan Ağaç Nesnesi (Client): 10000
Toplam Yaratılan Sinek Sıklet (Paylaşılan): 2
*/
              

Davranışsal Desenler (Behavioral Patterns) Genel Bilgi

Dinamik Etkileşim: İletişim ve Sorumluluk Yönetimi

Davranışsal Desenler, nesneler arasındaki karmaşık etkileşimleri, iletişim protokollerini ve sorumluluk akışını ( flow ) organize ederek sistemin esnekliğini ve sürdürülebilirliğini artırmaya odaklanan mimari çözümlerdir.

Bu desenler, sadece kodun fiziksel yapısıyla değil; nesnelerin çalışma anında ( runtime ) nasıl davrandığı ve birbirleriyle hangi mantıksal kurallar dahilinde konuştuğuyla ilgilenir.

Temel Mühendislik Öğüdü: Bir görev birden fazla nesnenin işbirliğini gerektiriyorsa, bu nesneleri birbirine körü körüne bağlamak yerine, aralarındaki bilgi akışını standartlaştırılmış bir kalıba oturtun.

Temel Felsefe: Davranışsal Düzeyde Gevşek Bağlılık

Davranışsal Desenlerin çekirdek felsefesi, Oluşturucu ve Yapısal desenlerdeki gevşek bağlılık ( loose coupling ) ilkesini, nesnelerin operasyonel süreçlerine taşımaktır:

Sorumlulukların Ayrılması (SoC): Her nesnenin sadece kendi uzmanlık alanından sorumlu olmasını ( Single Responsibility ) sağlarken, bu uzmanlıkların karmaşık bir hedef doğrultusunda nasıl senkronize olacağını tanımlar.

İletişim Soyutlaması: Bir isteği başlatan tarafı ( Sender ), o isteği yerine getiren taraftan ( Receiver ) ayırır. Örneğin; Observer deseni sayesinde bir nesne, kendisini kimin izlediğini bilmeden tüm dünyaya haber yayabilir.

Algoritma Esnekliği: Strategy gibi desenlerle, bir problemin çözüm yollarını (algoritmaları) çalışma anında koşullara göre dinamik olarak değiştirebilme yeteneği sunar.

Dinamik İş Akışının Mimari Yönetimi

Bu desenler, yazılımın yaşam döngüsündeki dinamik süreçler için şu mühendislik şablonlarını sunar:

İstek İşleme: Bir eylemi nesneye dönüştürerek ( Command ) geri alınabilir hale getirir veya bir isteği sırayla işleyiciler zincirinden ( Chain of Responsibility ) geçirerek esnek bir karar mekanizması kurar.

Durum ve Bellek Yönetimi: Nesnenin iç durumu değiştikçe davranışını otomatik günceller ( State ) veya geçmiş durumları kaydedip geri yükleyerek ( Memento ) sistemdeki undo/redo mantığını basitleştirir.

Karmaşık İlişki Koordinasyonu: Nesne grupları arasındaki çapraz bağımlılıkları merkezi bir arabulucuya ( Mediator ) devreder veya koleksiyonların iç yapısını gizleyerek öğeler üzerinde standart bir gezinme ( Iterator ) sağlar.

Sonuç olarak Davranışsal Desenler, yazılımın sadece "ne olduğunu" değil, "nasıl tepki verdiğini" belirleyen, sistemi zeki ve esnek bir organizmaya dönüştüren stratejik akıllardır.

Sorumluluk Zinciri Deseni (Chain of Responsibility Pattern) Örnek Uygulama ve Detaylı Açıklama

Dinamik İşleme Hattı: İsteklerin Zincirleme Akışı

Sorumluluk Zinciri Deseni, bir isteğin ( request ) o isteği işleyebilecek potansiyel nesnelerden oluşan mantıksal bir zincir boyunca aktarılmasını sağlayan davranışsal bir mimaridir.

Karar Verme Yetkisi: Bu desen, isteği gönderen tarafı ( client ) ile isteği karşılayan tarafı ( handler ) birbirinden kesin olarak ayırır. Zincirdeki her bir halka (alıcı), kendisine ulaşan isteği inceleyerek onu işleyip işlemeyeceğine bizzat kendi karar verir.

Eğer bir işleyici isteği o anki koşullarda sonuçlandıramazsa, isteği otomatik olarak zincirdeki bir sonraki halkaya devreder. Bu süreç, istek tamamen çözülene veya zincirin sonuna ulaşılana kadar kesintisiz bir şekilde devam eder.

Felsefi Amaç: Tam Bağımsızlık ve Gevşek Bağlılık

Sorumluluk Zinciri'nin çekirdek vizyonu, sistemdeki gevşek bağlılığı ( loose coupling ) en üst düzeye çıkararak bileşenleri özgürleştirmektir:

Mutlak Bağımsızlık: İstemci, isteğini kimin, hangi koşulda veya hangi sınıfta işleyeceğini bilmek zorunda değildir. İsteği sadece zincirin "giriş kapısına" bırakır. Bu durum, istemci kodun alt seviye işleme mantığından tamamen yalıtılmasını sağlar.

Dinamik İş Akışı: Zincirdeki halkaların sırası, sayısı ve türü uygulamanın çalışma anında ( runtime ) değiştirilebilir. Yeni bir güvenlik kontrolü veya loglama adımı eklemek, mevcut istemci kodunda tek bir satır bile değiştirmeyi gerektirmez.

Mühendislik Standartları: Tek Sorumluluk İlkesi

Odaklanmış İşleyiciler: Her bir işleyici nesnesi, sadece spesifik bir görevden ( örneğin sadece kimlik doğrulama veya sadece yetki kontrolü ) sorumludur. Bu, Tek Sorumluluk Prensibi ( SRP ) uyarınca her bileşenin temiz, test edilebilir ve basit kalmasını sağlar.

Sonuç olarak Sorumluluk Zinciri, karmaşık karar mekanizmalarını devasa if/else bloklarından kurtarıp, onları esnek, modüler ve yönetilebilir bir işlem hattına dönüştüren ileri düzey bir tasarım stratejisidir.

Chain of Responsibility Pattern Sorumluluk Zinciri Deseni Örneği

// 1. İşleyici (Handler) Arayüzü (Soyut Sınıf)
class SiparisIsleyici {
    constructor() {
        this.sonrakiIsleyici = null;
    }

    sonrakiyiAyarla(isleyici) {
        this.sonrakiIsleyici = isleyici;
        // Zincirleme için 'this' döndürülür
        return isleyici; 
    }

    // Zincirdeki her nesnenin uygulaması gereken temel metot
    isle(siparis) {
        if (this.sonrakiIsleyici) {
            // Eğer işleyemezse veya işi biterse, bir sonraki işleyiciye aktar.
            return this.sonrakiIsleyici.isle(siparis);
        }
        return siparis; // Zincir bitti, son siparişi döndür.
    }
}

// 2. Somut İşleyici A: Stok Kontrolü
class StokKontrolIsleyicisi extends SiparisIsleyici {
    isle(siparis) {
        if (siparis.stokYeterli === false) {
            console.error(`[STOK] Sipariş reddedildi: Stok yetersiz.`);
            return false;
        }
        console.log(`[STOK] Tamamlandı: Stok kontrolü başarılı.`);
        // Kendi işini yaptı, şimdi zincirde bir sonraki adıma geç.
        return super.isle(siparis); 
    }
}

// 3. Somut İşleyici B: Ödeme Onayı
class OdemeOnayIsleyicisi extends SiparisIsleyici {
    isle(siparis) {
        if (siparis.odemeBasarili === false) {
            console.error(`[ÖDEME] Sipariş reddedildi: Ödeme başarısız.`);
            return false;
        }
        console.log(`[ÖDEME] Tamamlandı: Ödeme onayı başarılı.`);
        return super.isle(siparis); 
    }
}

// 4. İstemci Kodu (Zinciri Kurma ve Çalıştırma)

// Zinciri kurma (Sıra önemlidir): Stok -> Ödeme
const stokIsleyici = new StokKontrolIsleyicisi();
const odemeIsleyici = new OdemeOnayIsleyicisi();

// Zincirleme: Stok, Ödeme'yi takip eder.
stokIsleyici.sonrakiyiAyarla(odemeIsleyici); 

// Örnek Sipariş 1: Başarılı Sipariş
const siparis1 = { id: 101, stokYeterli: true, odemeBasarili: true };
console.log("--- Sipariş 101 İşleniyor (Başarılı) ---");
const sonuc1 = stokIsleyici.isle(siparis1);
console.log(`Nihai Sonuç 1: ${sonuc1 ? 'İşlendi' : 'Hata'}`);

console.log("\n--- Sipariş 102 İşleniyor (Stok Hatası) ---");
// Örnek Sipariş 2: Stok Hatası (Zincir burada duracak)
const siparis2 = { id: 102, stokYeterli: false, odemeBasarili: true };
const sonuc2 = stokIsleyici.isle(siparis2);
console.log(`Nihai Sonuç 2: ${sonuc2 ? 'İşlendi' : 'Hata'}`);

/*
Çıktı:
--- Sipariş 101 İşleniyor (Başarılı) ---
[STOK] Tamamlandı: Stok kontrolü başarılı.
[ÖDEME] Tamamlandı: Ödeme onayı başarılı.
Nihai Sonuç 1: İşlendi

--- Sipariş 102 İşleniyor (Stok Hatası) ---
[STOK] Sipariş reddedildi: Stok yetersiz.
Nihai Sonuç 2: Hata
*/

Komut Deseni (Command Pattern) Örnek Uygulama ve Detaylı Açıklama

Eylemlerin Nesneleştirilmesi: Veri Olarak İşlemler

Komut Deseni, bir isteği veya operasyonu başlı başına bir nesne ( object ) olarak kapsülleyen davranışsal bir tasarım kalıbıdır.

Bağımsızlık Mimarisi: Bu kapsülleme sayesinde, isteği başlatan taraf ( Invoker / Çağırıcı ), bu isteği fiilen yerine getiren taraf ( Receiver / Alıcı ) hakkında hiçbir teknik detaya sahip olmak zorunda kalmaz.

Desen, eylemleri birer nesneye dönüştürdüğü için; bu eylemleri metotlara parametre olarak gönderebilir, bir kuyruğa (queue) alabilir, belirli bir zamana programlayabilir veya sistemin geçmişini yönetmek için saklayabilirsiniz.

Felsefi Amaç: Metot Çağrılarını Veriye Dönüştürmek

Komut deseninin temel felsefesi, "ne yapılacağı" bilgisini "nasıl yapılacağı" bilgisinden ayırarak bir işlem verisi oluşturmaktır:

Gevşek Bağlılık (Decoupling): İstemci ( örneğin bir kullanıcı arayüzü düğmesi ) ile Alıcı ( örneğin bir veritabanı motoru ) arasındaki doğrudan bağı kırılarak mimari bir esneklik sağlanır. İstemci sadece "Komutu yürüt" der; arkadaki karmaşık işleyişten tamamen yalıtılmıştır.

Geri Alma (Undo) Mekanizması: Komut nesneleri, yürütülen eylemi geri çevirmek için gereken tüm bilgileri ( önceki durum veya zıt işlem ) kendi bünyesinde saklar. Her komutun standart bir yurut() ve geriAl() metoduna sahip olması, profesyonel geri alma sistemlerinin kurulmasını sağlar.

İş Akışı Kontrolü: Kuyruklama ve Loglama

Eylemler artık nesne formunda olduğu için, sistemde yapılan her işlemin bir günlük kaydını (log) tutmak çocuk oyuncağı haline gelir. Bu kayıtlar, sistem çökmelerinden sonra işlemleri yeniden yürütmek veya kullanıcı aktivitelerini izlemek için mükemmel bir veri kaynağıdır.

Sonuç olarak Komut deseni, yazılım operasyonlarını kontrol edilebilir, ertelenebilir ve izlenebilir bağımsız birimlere dönüştüren yüksek seviyeli bir yönetim modelidir.

Command Pattern Komut Deseni Örneği

// 1. Alıcı (Receiver): Gerçek işi yapan nesne
class Isik {
    ac() {
        console.log("-> IŞIK: Açıldı.");
    }

    kapat() {
        console.log("-> IŞIK: Kapatıldı.");
    }
}

// 2. Komut Arayüzü
class Komut {
    yurut() {
        throw new Error("Uygulanmalı.");
    }
    // geriAl() eklenebilir, ancak bu örnekte sadece yurut kullanıyoruz.
}

// 3. Somut Komut A: Açma Eylemini Kapsüller
class IsikAcKomutu extends Komut {
    constructor(isik) {
        super();
        this.isik = isik; // Alıcıya referans
    }

    yurut() {
        // Alıcının metodunu çağırır
        this.isik.ac(); 
    }
}

// 4. Somut Komut B: Kapatma Eylemini Kapsüller
class IsikKapatKomutu extends Komut {
    constructor(isik) {
        super();
        this.isik = isik; // Alıcıya referans
    }

    yurut() {
        // Alıcının metodunu çağırır
        this.isik.kapat(); 
    }
}

// 5. Çağırıcı (Invoker): Komutu tutar ve tetikler.
class Kumanda {
    constructor() {
        this.acKomutu = null;
        this.kapatKomutu = null;
    }

    // Düğmeye bir komut nesnesi atar.
    dugmeAta(tip, komut) {
        if (tip === 'ac') {
            this.acKomutu = komut;
        } else if (tip === 'kapat') {
            this.kapatKomutu = komut;
        }
    }

    // Düğmeye basıldığında, hangi komut nesnesi atanmışsa onu yürütür.
    acDugmesineBasildi() {
        if (this.acKomutu) {
            console.log("KUMANDA: Açma düğmesine basıldı.");
            this.acKomutu.yurut();
        }
    }
    
    kapatDugmesineBasildi() {
        if (this.kapatKomutu) {
            console.log("KUMANDA: Kapatma düğmesine basıldı.");
            this.kapatKomutu.yurut();
        }
    }
}

// 6. İstemci Kodu (Client Code)
const oturmaOdasiIsigi = new Isik();
const kumanda = new Kumanda();

// Komut nesneleri yaratılır (Eylemler nesneleştirilir)
const acKomutu = new IsikAcKomutu(oturmaOdasiIsigi);
const kapatKomutu = new IsikKapatKomutu(oturmaOdasiIsigi);

// Komutlar Kumanda'daki düğmelere atanır.
kumanda.dugmeAta('ac', acKomutu);
kumanda.dugmeAta('kapat', kapatKomutu);

// Kullanıcı düğmelere basar. Kumanda, Işık nesnesini bilmeden sadece Komut'u yürütür.
kumanda.acDugmesineBasildi();
kumanda.kapatDugmesineBasildi();

/*
Çıktı:
KUMANDA: Açma düğmesine basıldı.
-> IŞIK: Açıldı.
KUMANDA: Kapatma düğmesine basıldı.
-> IŞIK: Kapatıldı.
*/

Tekrarlayıcı Deseni (Iterator Pattern) Örnek Uygulama ve Detaylı Açıklama

Erişim Standartı: Koleksiyon İç Yapısından Bağımsız Gezinme

Tekrarlayıcı Deseni, bir koleksiyon nesnesinin ( Aggregator ) içerdiği öğelere erişmek ve aralarında dolaşmak için standartlaştırılmış, ortak bir yol (arayüz) sağlayan davranışsal bir mimaridir.

Şeffaf Gezinme: Bu desen, koleksiyonun ( örneğin bir dizi, bağlı liste veya karmaşık bir ağaç yapısı ) dahili veri temsilini dış dünyaya (istemciye) ifşa etmeden, öğeler arasında kesintisiz gezinme ( traversing ) yeteneği kazandırır.

Desenin sunduğu en büyük mühendislik avantajı, sorumlulukların ayrılmasıdır. Koleksiyon sınıfı sadece veriyi depolamak ve yönetmekle ilgilenirken, bu veriler üzerinde nasıl "dolaşılacağı" mantığı tamamen Tekrarlayıcı sınıfına devredilir.

Felsefi Amaç: Erişim ve Depolama Mantığını Ayırmak

Tekrarlayıcı deseninin temel vizyonu, koleksiyonun "nasıl saklandığı" ile "nasıl okunduğu" arasındaki bağı kopararak mutlak bir esneklik sağlamaktır:

Gevşek Bağlılık ve Şeffaflık: İstemci kodu, verinin bellekte bir dizi (array) mi yoksa bir hash tablosu mu olarak tutulduğunu bilmek zorunda kalmaz. İstemci sadece sonraki() ve bittiMi() gibi evrensel metodları kullanır. Bu sayede koleksiyonun iç yapısı tamamen değişse bile istemci kodu etkilenmeden çalışmaya devam eder.

Çoklu Tekrarlama Gücü: Aynı veri kümesi üzerinde, birbirinin durumunu bozmadan çalışan birden fazla bağımsız gezinme sürecine olanak tanır. Her bir Tekrarlayıcı nesnesi, kendi "nerede kaldım?" bilgisini (indeksini) bağımsız olarak yönetir.

Mühendislik Çıkarımı: Evrensel Erişim Arayüzü

Standart İşlem: Farklı tipteki tüm koleksiyonlar ( örneğin bir ÜrünListesi ile bir PersonelKuyruğu ) için tek tip bir gezinme arayüzü sunar. Bu standartlaşma, kodun modülerliğini ve yeniden kullanılabilirliğini zirveye taşır.

Sonuç olarak Tekrarlayıcı deseni, veriye erişim süreçlerini bir protokole bağlayarak, karmaşık koleksiyon yapılarını "sade ve öngörülebilir" birer veri kaynağına dönüştürür.

Iterator Pattern Tekrarlayıcı Deseni Örneği

// 1. Somut Koleksiyon (Concrete Aggregator)
class KanalListesi {
    constructor() {
        this.kanallar = []; // Dahili veri yapısı (Dizi)
    }

    kanalEkle(kanal) {
        this.kanallar.push(kanal);
    }
    
    // 💡 Koleksiyon Arayüzü metodu: Kendi Tekrarlayıcısını yaratır ve döndürür.
    tekrarlaYarat() {
        return new KanalTekrarlayici(this.kanallar);
    }
}

// 2. Somut Tekrarlayıcı (Concrete Iterator)
class KanalTekrarlayici {
    constructor(kanallar) {
        this.kanallar = kanallar;
        this.mevcutIndeks = 0; // Gezinme durumunu tutar.
    }

    // Tekrarlayıcı Arayüzü metotları
    mevcut() {
        return this.kanallar[this.mevcutIndeks];
    }

    sonraki() {
        this.mevcutIndeks++;
    }

    bittiMi() {
        return this.mevcutIndeks >= this.kanallar.length;
    }
}

// 3. İstemci Kodu (Client Code)

const kanallar = new KanalListesi();
kanallar.kanalEkle("TRT 1");
kanallar.kanalEkle("Kanal D");
kanallar.kanalEkle("Show TV");

// 💡 İstemci, Koleksiyonun (KanalListesi) dahili yapısını (dizi) bilmeden gezinir.
const tekrarlayici = kanallar.tekrarlaYarat();

console.log("--- Kanallar Listesi ---");

while (!tekrarlayici.bittiMi()) {
    const kanal = tekrarlayici.mevcut();
    console.log(`Kanal: ${kanal}`);
    tekrarlayici.sonraki();
}

/*
Çıktı:
--- Kanallar Listesi ---
Kanal: TRT 1
Kanal: Kanal D
Kanal: Show TV
*/

Arabulucu Deseni (Mediator Pattern) Örnek Uygulama ve Detaylı Açıklama

Merkezi Yönetim: Doğrudan İletişimin Kısıtlanması

Arabulucu Deseni, birbiriyle sürekli etkileşim halinde olan nesne gruplarını ( Meslektaşlar / Colleagues ) merkeze alarak, bu nesnelerin birbirleriyle doğrudan iletişim kurmasını engelleyen yapısal bir koordinasyon modelidir.

İletişim Trafiği: Tüm mesajlaşma trafiği tek bir Arabulucu (Mediator) nesnesi üzerinden akar. Bir bileşende ( Component ) durum değişikliği olduğunda, bu değişikliği diğer bileşenlere kendisi duyurmaz; durumu Arabulucu'ya bildirir. Arabulucu ise hangi bileşenin bu duruma nasıl bir tepki vermesi gerektiğine karar vererek ilgili tarafları "tek tek" bilgilendirir.

Hava Trafiği Analojisi: Bu deseni bir havalimanındaki uçak kontrol kulesine benzetebilirsiniz. Pistteki uçaklar ( Meslektaşlar ) birbirleriyle doğrudan konuşmazlar; tüm kalkış ve iniş izinlerini kuleden ( Arabulucu ) alırlar. Kule, tüm uçakların konumunu bilerek kaosu önler.

Felsefi Amaç: Karışık Bağımlılık Ağlarını Temizlemek

Arabulucu deseninin temel varoluş amacı, sistemdeki çapraz bağımlılıkların ( spaghetti dependency ) yarattığı mimari kirliliği temizlemektir:

Sıkı Bağlılığı Giderme: Bir sistemdeki 10 farklı bileşenin birbirine doğrudan tepki vermesi durumu, matematiksel olarak $N \times N$ (yani 100) adet potansiyel bağlantı yaratır. Arabulucu, bu devasa bağlantı yığınını merkezi bir noktaya indirerek sistemin sürdürülebilirliğini ve test edilebilirliğini korur.

Sorumluluğun Ayrılması: Meslektaş sınıfları, diğer nesnelerin ne yaptığından veya nasıl çalıştığından haberdar olma yükünden kurtulur. Her nesne sadece kendi işini yapar; "başkasını ilgilendiren" kısımları Arabulucu'ya havale eder. Bu, her bir parçanın daha bağımsız ve yeniden kullanılabilir olmasını sağlar.

Mühendislik Avantajı: Tek Kontrol Noktası

Tüm etkileşim ve iş akışı mantığı Arabulucu sınıfının içine taşındığı için, sistemin genel davranışını değiştirmek istediğinizde onlarca sınıfa dokunmak yerine sadece tek bir merkeze bakmanız yeterli olur.

Sonuç olarak Arabulucu deseni, karmaşık nesne ağlarını yönetilebilir hale getiren, iletişimi disipline eden ve yazılımda "kaostan düzen yaratan" stratejik bir dengeleyicidir.

Mediator Pattern Arabulucu Deseni Örneği

// 1. Arabulucu Arayüzü (Basit bir sınıf olarak tanımlanabilir)
class DiyalogArabulucusu {
    meslekdasiBilgilendir(meslekdas, olay) {
        throw new Error("Uygulanmalı.");
    }
}

// 2. Meslektaş (Colleague) Temel Sınıfı
class Meslekdas {
    constructor(mediator) {
        // 💡 Arabulucu'ya referans tutar, diğer meslektaşlara değil.
        this.mediator = mediator; 
    }
}

// 3. Somut Meslektaş A: Kullanıcı Adı Girişi
class KullaniciAdiAlani extends Meslekdas {
    constructor(mediator) {
        super(mediator);
        this.text = "";
    }

    setText(yeniMetin) {
        this.text = yeniMetin;
        console.log(`[Kullanıcı Adı] Değişti: "${yeniMetin}"`);
        // Durum değişti: Arabulucu'yu bilgilendir.
        this.mediator.meslekdasiBilgilendir(this, "metinGirdisi"); 
    }

    getText() {
        return this.text;
    }
}

// 4. Somut Meslektaş B: Gönder Düğmesi
class GonderDugmesi extends Meslekdas {
    constructor(mediator) {
        super(mediator);
        this.aktif = false;
    }

    setAktif(aktifDurum) {
        this.aktif = aktifDurum;
        console.log(`[Gönder Düğmesi] Durum: ${this.aktif ? 'Aktif (Kullanılabilir)' : 'Pasif (Devre Dışı)'}`);
    }
}

// 5. Somut Arabulucu (Concrete Mediator): Koordinasyon Mantığı
class KimlikDogrulamaDiyalogu extends DiyalogArabulucusu {
    constructor(kullaniciAlani, gonderDugmesi) {
        super();
        this.kullaniciAlani = kullaniciAlani;
        this.gonderDugmesi = gonderDugmesi;
    }

    // 💡 Koordinasyon Mantığı: Tüm etkileşim burada kapsüllenir.
    meslekdasiBilgilendir(meslekdas, olay) {
        if (olay === "metinGirdisi") {
            const kullaniciAdi = this.kullaniciAlani.getText();
            
            // Eğer alan boşsa, düğmeyi Pasif yap; aksi takdirde Aktif yap.
            if (kullaniciAdi.length < 3) {
                this.gonderDugmesi.setAktif(false);
            } else {
                this.gonderDugmesi.setAktif(true);
            }
        }
    }
}

// 6. İstemci Kodu
const adAlani = new KullaniciAdiAlani(null); // Başlangıçta null atanır
const gonderBtn = new GonderDugmesi(null);

// Arabulucu yaratılır ve meslektaşları alır.
const diyalog = new KimlikDogrulamaDiyalogu(adAlani, gonderBtn);

// Meslektaşların Arabulucu referansı ayarlanır.
adAlani.mediator = diyalog; 
gonderBtn.mediator = diyalog;

// 1. Senaryo: Geçersiz Giriş (2 karakter)
console.log("--- Senaryo 1: Geçersiz Giriş ---");
adAlani.setText("Al"); // Kullanıcı Adı Alanı değişimi Arabulucu'yu tetikler.

// 2. Senaryo: Geçerli Giriş (4 karakter)
console.log("\n--- Senaryo 2: Geçerli Giriş ---");
adAlani.setText("Ahmet"); // Arabulucu, düğmeyi Aktif yapacaktır.

/*
Çıktı:
--- Senaryo 1: Geçersiz Giriş ---
[Kullanıcı Adı] Değişti: "Al"
[Gönder Düğmesi] Durum: Pasif (Devre Dışı)

--- Senaryo 2: Geçerli Giriş ---
[Kullanıcı Adı] Değişti: "Ahmet"
[Gönder Düğmesi] Durum: Aktif (Kullanılabilir)
*/
              

Hatıra Deseni (Memento Pattern) Örnek Uygulama ve Detaylı Açıklama

Durum Yönetimi: Kapsüllemeyi Bozmadan Kayıt Altına Alma

Hatıra Deseni, bir nesnenin ( Originator ) sahip olduğu iç durumu ( state ), o nesnenin mahremiyetini ve kapsüllemesini ( encapsulation ) ihlal etmeden harici bir birimde saklama yeteneği kazandıran mimari bir çözümdür.

Geriye Dönük Erişim: Kaydedilen bu anlık görüntüye ( Memento ), nesnenin ilerleyen süreçlerde önceki bir durumuna hatasız bir şekilde geri yüklenmesi ( Undo / Geri Alma ) amacıyla ihtiyaç duyulur.

Bu desen; modern metin editörleri ( Notepad++, VS Code ), grafik tasarım yazılımları ( Photoshop ) veya strateji oyunlarındaki "kayıt noktası" mekanizmalarını inşa etmek için kullanılan yegane standarttır.

Temel Mühendislik İkilemi ve Çözümü

Paradoks: Bir nesnenin durumunu kaydetmek için normalde o nesnenin tüm gizli (private) değişkenlerine erişmeniz gerekir. Ancak bu, nesnenin iç mantığını dış dünyaya açarak kapsülleme kuralını yerle bir eder.

Hatıra Çözümü: Desen, bu ikilemi durumu bir "kara kutu" olan Hatıra nesnesi içine gizleyerek çözer. Bu kutunun içeriğini kimse göremez; sadece kutuyu yaratan nesne onu tekrar açıp içindeki veriyi kullanabilir.

Felsefi Amaç: Güvenli ve Disiplinli Geçmiş Yönetimi

Kapsüllemeyi Koruma: Durumu kaydeden ( Originator ) ile saklayan ( Caretaker ) arasındaki iletişimi kısıtlar. Saklayıcı birim (Caretaker), elindeki Hatıra'nın içinde ne olduğunu asla bilmez; sadece onu rafta tutar ve istendiğinde geri verir.

Geri Alabilme Yeteneği: Sisteme, kullanıcı hatalarını telafi eden dinamik bir undo/redo ( geri al / yinele ) mekanizması kazandırır. Bu, özellikle çok adımlı ve karmaşık işlemlerde kullanıcı deneyimini (UX) zirveye taşır.

Tekrarlamadan Kaçınma: Durum saklama mantığını, asıl işi yapan nesneden ayırarak saklayıcıya devreder. Bu sayede asıl nesne (Originator), geçmişin yükünü taşımadan sadece kendi ana görevine odaklanabilir.

Sonuç olarak Hatıra deseni, yazılımda "hatanın telafisi vardır" ilkesini kapsülleme disipliniyle birleştiren, sistemin tarihsel tutarlılığını sağlayan profesyonel bir hafıza yönetimidir.

Memory Pattern Hatıra Deseni Örneği

// 1. Memento (Hatıra): Durumu kapsülleyen nesne
class MetinMemento {
    constructor(metin) {
        // 💡 İç durum (state) özel olarak saklanır.
        this.metin = metin; 
    }

    getMetin() {
        return this.metin;
    }
}

// 2. Originator (Oluşturan/Yaratan): Durumu olan nesne
class MetinEditoru {
    constructor(varsayilanMetin) {
        this.mevcutMetin = varsayilanMetin;
    }

    // Originator'a yeni metin eklenir (durum değişir)
    yaz(ekMetin) {
        this.mevcutMetin += " " + ekMetin;
        console.log(`[EDITOR] Metin güncellendi: "${this.mevcutMetin}"`);
    }

    // 💡 Durumu Kaydetme: Mevcut metni içeren bir Hatıra nesnesi yaratır.
    durumuKaydet() {
        console.log("[EDITOR] Durum kaydedildi.");
        return new MetinMemento(this.mevcutMetin);
    }

    // 💡 Durumu Geri Yükleme: Verilen Hatıra nesnesindeki duruma döner.
    durumuGeriYukle(memento) {
        this.mevcutMetin = memento.getMetin();
        console.log(`[EDITOR] Durum geri yüklendi: "${this.mevcutMetin}"`);
    }

    getMevcutMetin() {
        return this.mevcutMetin;
    }
}

// 3. Caretaker (Vasi/Yönetici): Hatıraları yönetir.
class GeriAlmaYoneticisi {
    constructor() {
        // Geçmiş durumları saklamak için bir yığın (stack) kullanılır.
        this.gecmis = []; 
    }

    ekle(memento) {
        this.gecmis.push(memento);
    }

    // En son kaydedilen durumu döndürür ve yığından çıkarır.
    geriAl() {
        if (this.gecmis.length > 1) {
            // Sonuncuyu geri alma işleminden sonra kullanmayacağız, bir öncesine döneceğiz.
            this.gecmis.pop(); 
        }
        return this.gecmis[this.gecmis.length - 1]; // Yeni son Hatıra
    }
}

// 4. İstemci Kodu (Client Code)
const editor = new MetinEditoru("Merhaba Dünya.");
const yonetici = new GeriAlmaYoneticisi();

// Adım 1: Başlangıç durumunu kaydet
yonetici.ekle(editor.durumuKaydet());

// Adım 2: İlk değişiklik
editor.yaz("Bugün hava çok güzel.");
yonetici.ekle(editor.durumuKaydet());

// Adım 3: İkinci değişiklik
editor.yaz("Yarın buluşalım.");
yonetici.ekle(editor.durumuKaydet());

// --- Geri Alma İşlemi ---
console.log("\n--- Geri Alma Başlıyor (UNDO) ---");

// Geri al: Son kayıttan (Yarın buluşalım) bir önceki duruma dönülür (Bugün hava çok güzel).
const geriAlinacakDurum = yonetici.geriAl();
editor.durumuGeriYukle(geriAlinacakDurum); // Metin: "Merhaba Dünya. Bugün hava çok güzel."

// Geri al 2: Bir önceki duruma dönülür (Merhaba Dünya).
const geriAlinacakDurum2 = yonetici.geriAl();
editor.durumuGeriYukle(geriAlinacakDurum2); // Metin: "Merhaba Dünya."

/*
Çıktı:
[EDITOR] Durum kaydedildi.
[EDITOR] Metin güncellendi: "Merhaba Dünya. Bugün hava çok güzel."
[EDITOR] Durum kaydedildi.
[EDITOR] Metin güncellendi: "Merhaba Dünya. Bugün hava çok güzel. Yarın buluşalım."
[EDITOR] Durum kaydedildi.

--- Geri Alma Başlıyor (UNDO) ---
[EDITOR] Durum geri yüklendi: "Merhaba Dünya. Bugün hava çok güzel."
[EDITOR] Durum geri yüklendi: "Merhaba Dünya."
*/
                          

Gözlemci Deseni (Observer Pattern) Örnek Uygulama ve Detaylı Açıklama

Yayıncı-Abone Mekanizması: Otomatik Bildirim Sistemi

Gözlemci Deseni, bir nesnenin ( Subject / Konu ) durumu değiştiğinde, ona göbekten bağlı olan tüm diğer nesnelere ( Observer / Gözlemci ) bu değişikliğin otomatik olarak duyurulmasını sağlayan gelişmiş bir iletişim mekanizmasıdır.

İletişim Soyutlaması: Konu nesnesi, durumu değişen asıl kaynaktır. Ancak bu kaynak, kendisine kimlerin abone olduğunu veya bu abonelerin kimliklerini bilmek yerine, sadece standart bir arayüz ( notify / bildir metodu) kullanarak haberi dünyaya yayar.

Gözlemciler ise ilgilendikleri konuya dinamik olarak abone olurlar. Bildirim onlara ulaştığı an, her biri kendi uzmanlık alanına göre davranışlarını günceller.

Felsefi Amaç: Durum Değişikliğini Evrensel Olarak Yayınlamak

Gözlemci deseninin temel vizyonu, sistemdeki parçaları birbirine düğümlemeden ( publish/subscribe ) veri akışını yönetmektir:

Gevşek Bağlılık (Loose Coupling): Konu nesnesi, abonelerin ne iş yaptığından tamamen habersizdir. Aradaki tek bağ, ortak bir Observer Arayüzü'dür. Bu sayede, sistemi kapatmadan yeni bir gözlemci eklemek veya mevcut birini devreden çıkarmak Konu nesnesi için hiçbir risk teşkil etmez.

Bütünsel Tutarlılık: Bir veri ( örneğin bir hisse senedi fiyatı ) güncellendiğinde, bu veriye bağlı olan grafiklerin, tabloların ve uyarı bildirimlerinin anlık ve tutarlı şekilde senkronize olmasını garanti eder. Bu, veri kirliliğini ve manuel güncelleme hatalarını ortadan kaldırır.

Mühendislik Esnekliği: Dinamik Abonelik Yönetimi

Runtime Özgürlüğü: Gözlemciler, uygulama çalışırken ( runtime ) istedikleri saniyede konuya dahil olabilir ( attach ) veya sessizce ayrılabilirler ( detach ). Bu, sistemin kullanıcı etkileşimlerine göre şekil değiştirmesine olanak tanıyan devrimsel bir özelliktir.

Sonuç olarak Gözlemci deseni, nesneler arası "bağımlılığı değil, farkındalığı" yöneten, modern ve dinamik yazılımların en güçlü sinir sistemidir.

Observer Pattern Gözlemci Deseni Örneği

// 1. Konu (Subject): Hisse Senedi (Yayıncı)
class HisseSenedi {
    constructor(ad, fiyat) {
        this.ad = ad;
        this.fiyat = fiyat;
        this.aboneler = []; // Gözlemci listesi
    }

    aboneOl(gozlemci) {
        this.aboneler.push(gozlemci);
        console.log(`[KONU] Yeni abone eklendi: ${gozlemci.ad}`);
    }

    // Durum değiştiğinde tüm gözlemcilere bildirim gönderir.
    bildir() {
        console.log(`[KONU] Hisse fiyatı değişti, ${this.aboneler.length} aboneye bildiriliyor.`);
        for (const gozlemci of this.aboneler) {
            gozlemci.guncelle(this.ad, this.fiyat); // Gözlemcinin metodunu çağırır.
        }
    }

    fiyatGuncelle(yeniFiyat) {
        if (this.fiyat !== yeniFiyat) {
            this.fiyat = yeniFiyat;
            this.bildir(); // Fiyat değiştiği an bildirimi tetikle.
        }
    }
}

// 2. Gözlemci (Observer) Arayüzü (Sadece guncelle metodu bekler)

// 3. Somut Gözlemci A: Grafik Bileşeni
class Grafik extends HisseSenedi {
    constructor(ad) {
        this.ad = ad;
    }
    
    guncelle(hisseAd, yeniFiyat) {
        console.log(`[GRAFİK] ${hisseAd} grafiği güncellendi. Yeni Fiyat: ${yeniFiyat} TL`);
        // Gerçek uygulamada burada grafik çizimi yapılır.
    }
}

// 4. Somut Gözlemci B: Bildirim Penceresi
class Bildirim extends HisseSenedi {
    constructor(ad) {
        this.ad = ad;
    }
    
    guncelle(hisseAd, yeniFiyat) {
        if (yeniFiyat > 100) {
            console.warn(`[BİLDİRİM] Dikkat! ${hisseAd} 100 TL'nin üzerine çıktı!`);
        }
    }
}

// 5. İstemci Kodu (Client Code)

const appleHissesi = new HisseSenedi("AAPL", 95);

const grafik1 = new Grafik("Apple Grafiği");
const bildirim1 = new Bildirim("Fiyat Uyarıcısı");

// Gözlemciler, Konu'ya abone olur.
appleHissesi.aboneOl(grafik1);
appleHissesi.aboneOl(bildirim1);

console.log("\n--- Durum Değişikliği (1. Güncelleme) ---");
appleHissesi.fiyatGuncelle(98); // Bildirim tetiklenir

console.log("\n--- Durum Değişikliği (2. Güncelleme: Kritik) ---");
appleHissesi.fiyatGuncelle(105); // Bildirim ve Grafik güncellenir

/*
Çıktı:
[KONU] Yeni abone eklendi: Apple Grafiği
[KONU] Yeni abone eklendi: Fiyat Uyarıcısı

--- Durum Değişikliği (1. Güncelleme) ---
[KONU] Hisse fiyatı değişti, 2 aboneye bildiriliyor.
[GRAFİK] AAPL grafiği güncellendi. Yeni Fiyat: 98 TL

--- Durum Değişikliği (2. Güncelleme: Kritik) ---
[KONU] Hisse fiyatı değişti, 2 aboneye bildiriliyor.
[GRAFİK] AAPL grafiği güncellendi. Yeni Fiyat: 105 TL
[BİLDİRİM] Dikkat! AAPL 100 TL'nin üzerine çıktı!
*/
                                  

Durum Deseni (State Pattern) Örnek Uygulama ve Detaylı Açıklama

Dinamik Kişilik: Nesne Durumuna Göre Değişen Davranışlar

Durum Deseni, bir nesnenin ( Context / Bağlam ) o anki içsel durumuna bağlı olarak çalışma anında tamamen farklı davranışlar sergilemesini sağlayan stratejik bir modeldir.

Durumların Kapsüllenmesi: Bu mimari, nesnenin her bir olası halini, o hale özgü davranışları ve bir sonraki aşamaya geçiş kurallarını içeren bağımsız sınıflar ( Concrete State / Somut Durum ) olarak paketler.

Nesnenin durumu değiştiğinde, ana nesne (Context) sadece yeni bir durum nesnesine referans atar. Böylece nesne, dışarıdan bakıldığında sanki "sınıfını değiştirmiş" gibi farklı tepkiler vermeye başlar.

Felsefi Amaç: Koşul Karmaşasından (Spaghetti Code) Kaçış

Durum deseninin temel vizyonu, sistemin damarlarını tıkayan devasa if/else veya switch/case bloklarını temizleyerek nesne yönelimli bir zarafet sunmaktır:

Tek Sorumluluk Prensibi (SRP): Her bir durumun mantığı ve geçiş kuralları kendi özel sınıfında izole edilir. Bağlam nesnesi (Context), karmaşık mantıkla uğraşmak yerine sadece mevcut durumu temsil eden nesneyi "elinde tutma" sorumluluğunu üstlenir.

Açık/Kapalı Prensibi (OCP): Sisteme yeni bir durum ( örneğin bir sipariş sürecine "İptal Edildi" durumu ) eklemek istediğinizde, mevcut kodları bozmanıza gerek kalmaz. Sadece yeni bir Somut Durum Sınıfı oluşturursunuz. Bu, sistemi genişlemeye sınırsızca açık hale getirir.

Mühendislik Gücü: Çalışma Zamanında Evrim

Dinamik Karakter: Nesnenin karakteri ve vereceği tepkiler derleme zamanında taşlaşmaz. Uygulama çalışırken ( runtime ) gerçekleşen olaylara göre nesne, durum nesneleri arasında geçiş yaparak evrimleşir.

Sonuç olarak Durum deseni, yazılımda "durum makinelerini" ( finite state machines ) modüler ve okunaklı sınıflara dönüştüren, kodun bakım maliyetini düşüren ileri düzey bir organizasyon biçimidir.

State Pattern Durum Deseni Örneği

// 1. Durum Arayüzü (State)
class TrafikLambaDurumu {
    goster() { throw new Error("Uygulanmalı."); }
    gecis(lamba) { throw new Error("Uygulanmalı."); } // Bir sonraki duruma geçişi yönetir.
}

// 2. Somut Durum A: Kırmızı Işık
class KirmiziDurum extends TrafikLambaDurumu {
    goster() {
        return "KIRMIZI IŞIK: Dur!";
    }

    gecis(lamba) {
        console.log("-> Kırmızıdan Sarıya geçiliyor...");
        // 💡 Bağlam nesnesinin durumunu değiştir.
        lamba.durumAyarla(new SariDurum()); 
    }
}

// 3. Somut Durum B: Sarı Işık
class SariDurum extends TrafikLambaDurumu {
    goster() {
        return "SARI IŞIK: Hazırlan.";
    }

    gecis(lamba) {
        console.log("-> Sarıdan Yeşile geçiliyor...");
        lamba.durumAyarla(new YesilDurum());
    }
}

// 4. Somut Durum C: Yeşil Işık
class YesilDurum extends TrafikLambaDurumu {
    goster() {
        return "YEŞİL IŞIK: Geç!";
    }

    gecis(lamba) {
        console.log("-> Yeşilden Kırmızıya geçiliyor...");
        lamba.durumAyarla(new KirmiziDurum());
    }
}

// 5. Bağlam (Context): Trafik Lambası
class TrafikLambasi {
    constructor() {
        // Başlangıç durumu: Kırmızı
        this.durum = new KirmiziDurum(); 
    }

    // İstemcinin kullandığı tek metot.
    lambaGoster() {
        return this.durum.goster();
    }

    // 💡 Bağlamın durumunu değiştirir. Sadece Bağlam veya Durumlar bu metodu çağırabilir.
    durumAyarla(yeniDurum) {
        this.durum = yeniDurum;
    }

    // Mevcut durumun geçiş metodunu çağırır.
    durumuDegistir() {
        this.durum.gecis(this); // Mevcut durumu, bir sonraki duruma geçişini kendisi yönetir.
    }
}

// 6. İstemci Kodu (Client Code)
const lamba = new TrafikLambasi();

// 1. İşlem
console.log(`Mevcut Durum: ${lamba.lambaGoster()}`); // Kırmızı
lamba.durumuDegistir(); // Kırmızı -> Sarı
console.log(`Mevcut Durum: ${lamba.lambaGoster()}`);

// 2. İşlem
lamba.durumuDegistir(); // Sarı -> Yeşil
console.log(`Mevcut Durum: ${lamba.lambaGoster()}`);

// 3. İşlem
lamba.durumuDegistir(); // Yeşil -> Kırmızı
console.log(`Mevcut Durum: ${lamba.lambaGoster()}`);

/*
Çıktı:
Mevcut Durum: KIRMIZI IŞIK: Dur!
-> Kırmızıdan Sarıya geçiliyor...
Mevcut Durum: SARI IŞIK: Hazırlan.
-> Sarıdan Yeşile geçiliyor...
Mevcut Durum: YEŞİL IŞIK: Geç!
-> Yeşilden Kırmızıya geçiliyor...
Mevcut Durum: KIRMIZI IŞIK: Dur!
*/
        

Strateji Deseni (Strategy Pattern) Örnek Uygulama ve Detaylı Açıklama

Değişebilir Algoritmalar: Dinamik Çözüm Seçimi

Strateji Deseni, belirli bir problemi çözmek için kullanılabilecek birbirinin alternatifi olan algoritma ailelerini ( strategies ) tanımlayan ve bu ailedeki her bir algoritmayı standart bir arayüz arkasında kapsülleyen davranışsal bir desendir.

Bağımsız Uygulama: Bu desen sayesinde bir algoritmanın teknik uygulama mantığı, o algoritmayı fiilen kullanan ana koddan ( Context / Bağlam ) tamamen ayrılır.

Eğer bir sınıfın içerisinde farklı senaryolara göre sürekli dallanıp budaklanan devasa if/else veya switch/case blokları görüyorsanız, bu durum mimarinin Strateji Deseni'ne ihtiyaç duyduğunun en net kanıtıdır.

Felsefi Amaç: Algoritma Yönetiminde Esneklik

Strateji deseninin temel vizyonu, "nasıl yapılacağı" kararını merkezileştirmek ve bu kararı uygulama anına kadar erteleyebilmektir:

Dinamik Değişim (Runtime Agility): Bağlam nesnesi, belirli bir işlem yoluna göbekten bağlı kalmak yerine, elinde o anki ihtiyaca uygun bir Strateji Nesnesi referansı tutar. Bu referans çalışma anında ( runtime ) değiştirildiği an, sistemin tüm davranışı saniyeler içinde güncellenir.

Tek Sorumluluk ve OCP Uyumu: Her bir hesaplama yöntemi veya iş mantığı, kendi özel strateji sınıfı içinde izole edilir. Yeni bir yöntem ( örneğin yeni bir ödeme kanalı veya kargo hesaplama türü ) eklemek istediğinizde mevcut kodlara dokunmazsınız; sadece yeni bir strateji sınıfı yaratırsınız.

Mühendislik Avantajı: Enjeksiyon ve Sadelik

Kullanım Kolaylığı ve Enjeksiyon: İstemci, sadece o anki iş gereksinimine uygun olan algoritmayı seçer ve Bağlam nesnesine enjekte eder ( dependency injection ). İstemci, seçtiği bu "aklımın" arka plandaki karmaşık matematiksel detaylarıyla uğraşmak zorunda kalmaz.

Sonuç olarak Strateji deseni, yazılımı "taşlaşmış kararlardan" kurtarıp, her duruma uyum sağlayabilen "akıllı ve değiştirilebilir bir zekaya" dönüştüren profesyonel bir tasarım standardıdır.

Strategy Pattern Strateji Deseni Örneği

// 1. Strateji Arayüzü
class KargoUcretiHesapla {
    hesapla(agirlik) {
        throw new Error("Uygulanmalı.");
    }
}

// 2. Somut Strateji A: Normal Kargo
class NormalKargo extends KargoUcretiHesapla {
    hesapla(agirlik) {
        // Basit formül: 5 TL sabit + ağırlık * 2 TL
        return 5 + (agirlik * 2);
    }
}

// 3. Somut Strateji B: Hızlı Kargo
class HizliKargo extends KargoUcretiHesapla {
    hesapla(agirlik) {
        // Daha pahalı formül: 15 TL sabit + ağırlık * 3.5 TL
        return 15 + (agirlik * 3.5);
    }
}

// 4. Bağlam (Context): Kargo Yöneticisi
class KargoYoneticisi {
    constructor(strateji) {
        // Başlangıç stratejisini tutar.
        this.strateji = strateji; 
    }

    // 💡 Çalışma anında stratejiyi değiştirme metodu
    stratejiAyarla(yeniStrateji) {
        this.strateji = yeniStrateji;
    }

    // İstemciden gelen isteği mevcut stratejiye delege eder.
    ucretHesapla(agirlik) {
        console.log(`[YÖNETİCİ] Ağırlık ${agirlik} kg için hesaplama yapılıyor...`);
        // Delegasyon
        return this.strateji.hesapla(agirlik); 
    }
}

// 5. İstemci Kodu (Client Code)

const kargoAgirligi = 10; // 10 kg paket

// Bağlam oluşturulur ve başlangıç stratejisi (Normal Kargo) enjekte edilir.
const yonetici = new KargoYoneticisi(new NormalKargo());

// 1. Senaryo: Normal Kargo
let ucret1 = yonetici.ucretHesapla(kargoAgirligi); // 5 + (10*2) = 25 TL
console.log(`Normal Kargo Ücreti: ${ucret1} TL`);

// 💡 Dinamik Değişim: İstemci, çalışma anında stratejiyi değiştirir.
yonetici.stratejiAyarla(new HizliKargo());

// 2. Senaryo: Hızlı Kargo
let ucret2 = yonetici.ucretHesapla(kargoAgirligi); // 15 + (10*3.5) = 50 TL
console.log(`Hızlı Kargo Ücreti: ${ucret2} TL`);

/*
Çıktı:
[YÖNETİCİ] Ağırlık 10 kg için hesaplama yapılıyor...
Normal Kargo Ücreti: 25 TL
[YÖNETİCİ] Ağırlık 10 kg için hesaplama yapılıyor...
Hızlı Kargo Ücreti: 50 TL
*/

Şablon Metodu Deseni (Template Method Pattern) Örnek Uygulama ve Detaylı Açıklama

Algoritma İskeleti: Sabit Akış ve Değişken Adımlar

Şablon Metodu Deseni, karmaşık bir operasyonu gerçekleştiren algoritmanın genel iskeletini bir ana metot içinde tanımlayan ve bu adımların icra sırasını garanti altına alan bir tasarım kalıbıdır.

Süreci Sabitleme: Bu şablon metodu, genellikle soyut bir üst sınıfta yer alır ve algoritmanın temel mantığını kilitler. Algoritmanın içindeki bazı spesifik adımlar ise soyut metotlar veya kancalar ( hooks ) olarak bırakılarak, bunların nasıl doldurulacağı Somut Alt Sınıfların ( Concrete Subclasses ) uzmanlığına devredilir.

Bu desen, bir sürecin değişmeyen, genel geçer kısımlarını üst sınıfta muhafaza ederek kod tekrarını minimize ederken; değişmesi muhtemel kısımları alt sınıflara delege ederek esnek bir özelleştirme zemini hazırlar.

Felsefi Amaç: Algoritma Yapısını Standartlaştırmak

Şablon Metodu deseninin temel vizyonu, bir sürecin "omurgasını" korurken "uzuvlarının" farklılaşmasına izin vermektir:

Kod Tekrarını Önleme: Büyük ölçüde aynı adımları izleyen ancak küçük nüanslarla birbirinden ayrılan operasyonlar için ortak mantığı üst sınıfa taşır. Bu sayede, aynı kod bloklarının her alt sınıfta yeniden yazılmasının önüne geçilir ve merkezi bir bakım noktası oluşturulur.

Kontrolün Tersine Çevrilmesi (IoC): Algoritmanın sırasını ve yönetimini üst sınıf üstlenir. Alt sınıflar, hiyerarşik bir hiyerarşi içinde sadece kendilerine ayrılan boşlukları doldurabilirler; ancak algoritmanın genel akışını veya adımların sırasını asla değiştiremezler.

Mühendislik Disiplini: Kancalar ve Özelleştirme

Hiyerarşik Özelleştirme: Alt sınıfların, algoritmanın tamamını sil baştan kurgulamak yerine, sadece ihtiyaç duydukları kritik noktaları ( hook methods ) geçersiz kılarak ( override ) sisteme entegre olmalarını sağlar.

Sonuç olarak Şablon Metodu deseni, yazılımda "standart bir prosedür" dayatırken, bu prosedürün içindeki detayların "kişiselleştirilmesine" izin veren, disiplin ile esnekliği dengeleyen profesyonel bir mimaridir.

Template Method Pattern Şablon Metodu Desen Örneği

// 1. Soyut Sınıf (Abstract Class) - İçecek Hazırlama
class IcecekHazirlama {
    // 💡 Şablon Metodu: Algoritmanın iskeleti (final metot).
    hazirla() {
        this.suyuKaynat();
        this.icecegiDemle();        // Soyut adım, alt sınıf uygular
        this.bardagaKoy();
        
        // Kanca Metodu: İsteğe bağlı
        if (this.musteriEklentiIstiyor()) {
            this.eklentileriKoy();  // Soyut adım, alt sınıf uygular
        }
    }

    // Ortak Adımlar (Değişmeyen Kısımlar)
    suyuKaynat() {
        console.log("-> 1. Suyu Kaynatma.");
    }

    bardagaKoy() {
        console.log("-> 3. Hazırlanan içeceği bardağa koyma.");
    }
    
    // 💡 Kanca Metodu (Hook): Varsayılan olarak true döner, alt sınıf geçersiz kılabilir.
    musteriEklentiIstiyor() {
        return true; 
    }

    // Soyut Adımlar (Alt sınıfların zorunlu uygulaması gereken)
    icecegiDemle() {
        throw new Error("Alt sınıf uygulamalı.");
    }

    eklentileriKoy() {
        throw new Error("Alt sınıf uygulamalı.");
    }
}

// 2. Somut Sınıf A: Kahve
class KahveHazirlama extends IcecekHazirlama {
    icecegiDemle() {
        console.log("-> 2. Kahveyi filtre ile demleme.");
    }

    eklentileriKoy() {
        console.log("-> 4. Şeker ve Süt ekleme.");
    }
}

// 3. Somut Sınıf B: Sade Çay (Kanca Metodunu geçersiz kılan)
class SadeCayHazirlama extends IcecekHazirlama {
    icecegiDemle() {
        console.log("-> 2. Çay poşetini sıcak suda bekletme.");
    }

    eklentileriKoy() {
        console.log("-> 4. Limon dilimi ekleme.");
    }
    
    // 💡 Kancayı Geçersiz Kılma: Müşteri eklenti istemiyor varsayımı.
    musteriEklentiIstiyor() {
        console.log("[Kanca] Çay için eklenti istemiyor.");
        return false; 
    }
}

// 4. İstemci Kodu (Client Code)
console.log("--- Kahve Hazırlanıyor ---");
const kahve = new KahveHazirlama();
kahve.hazirla(); // Adımların sırası üst sınıf tarafından kontrol edilir.

console.log("\n--- Sade Çay Hazırlanıyor ---");
const cay = new SadeCayHazirlama();
cay.hazirla(); // Kanca metodu sayesinde 4. adım atlanır.

/*
Çıktı:
--- Kahve Hazırlanıyor ---
-> 1. Suyu Kaynatma.
-> 2. Kahveyi filtre ile demleme.
-> 3. Hazırlanan içeceği bardağa koyma.
-> 4. Şeker ve Süt ekleme.

--- Sade Çay Hazırlanıyor ---
-> 1. Suyu Kaynatma.
-> 2. Çay poşetini sıcak suda bekletme.
-> 3. Hazırlanan içeceği bardağa koyma.
[Kanca] Çay için eklenti istemiyor.
*/

Ziyaretçi Deseni (Visitor Pattern) Örnek Uygulama ve Detaylı Açıklama

Operasyonel Ayrıştırma: Nesne Yapısını Bozmadan Yeni Yetenekler

Ziyaretçi Deseni, karmaşık bir nesne yapısında ( elementler ) bulunan öğeler üzerinde yeni operasyonlar tanımlamanız gerektiğinde, bu öğelerin mevcut sınıflarını ve kaynak kodlarını değiştirmek zorunda kalmamak için kullanılan stratejik bir desendir.

Dışarıdan Müdahale: Bu desen, yeni fonksiyonları nesnelerin kendi içine yazmak yerine, yapının öğelerini "ziyaret eden" ve onlara yeni yetenekler kazandıran bağımsız bir sınıfa ( Visitor / Ziyaretçi ) taşır.

Temel fikir; bir sınıfın üzerine yeni bir görev yüklemek istediğinizde o sınıfın kapısını çalmak yerine, Ziyaretçi nesnesinin o sınıfa özel metodunu çağırmaktır. Ziyaretçi, hangi öğeyi ziyaret ettiğine bağlı olarak davranışını otomatik olarak belirler ( Double Dispatch / Çift Yönlü Gönderme ).

Felsefi Amaç: Veri Yapısı ve İşlem Mantığını Ayırmak

Ziyaretçi deseninin temel vizyonu, nesneleri sadece "veri taşıyıcıları" olarak bırakıp, onlarla ne yapılacağı kararını tamamen dış dünyaya bırakmaktır:

Açık/Kapalı Prensibi (OCP): Nesne yapısını oluşturan sınıflar ( örneğin Çalışan, Yönetici, Departman gibi elementler ) değişime tamamen kapalıdır. Sisteme "Vergi Hesaplama" veya "Performans Raporlama" gibi tamamen yeni bir işlem eklemek istediğinizde mevcut sınıfların tek bir satırına bile dokunmazsınız. Sadece yeni bir Ziyaretçi Sınıfı oluşturarak sistemi genişletirsiniz.

İşlemlerin Merkezi Birleşimi: Birbirinden farklı sınıflar üzerinde çalışan ancak aynı amaca hizmet eden tüm operasyonları ( örneğin Raporlama Ziyaretçisi'nin her departman için ürettiği farklı raporlar ) tek bir merkezde toplar. Bu, kodun dağılmasını önleyerek bakım maliyetini düşürür.

Mühendislik Gücü: Karmaşık Hiyerarşilerde Standartlaşma

Hiyerarşi Üzerinde İşlem: Özellikle ağaç benzeri karmaşık nesne hiyerarşilerinde gezinirken, her bir öğenin kendine özgü türüne göre farklı mantıklar uygulamanın en temiz yoludur. Ziyaretçi, nesne yapısının içinde dolaşırken her düğüme uğrar ve o düğümün tipine göre doğru işlemi enjekte eder.

Sonuç olarak Ziyaretçi deseni, yazılımda "veri" ile "fonksiyonu" birbirinden bağımsız olarak büyüten, mevcut yapıları sarsmadan onlara sınırsız yeni özellik katan profesyonel bir mimari köprüdür.

Visitor Pattern Ziyaretçi Desen Örneği

// 1. Element Arayüzü
class KurumsalElement {
    // Tüm elementlerin Ziyaretçiyi kabul etmesi gerekir.
    kabulEt(visitor) {
        throw new Error("Uygulanmalı.");
    }
}

// 2. Somut Element A: Çalışan
class Calisan extends KurumsalElement {
    constructor(ad, maas) {
        super();
        this.ad = ad;
        this.maas = maas;
    }

    // 💡 Çift Gönderme (Double Dispatch): Kendi tipini Ziyaretçi'ye bildirir.
    kabulEt(visitor) {
        visitor.ziyaretEtCalisan(this);
    }
}

// 3. Somut Element B: Yönetici
class Yonetici extends KurumsalElement {
    constructor(ad, maas) {
        super();
        this.ad = ad;
        this.maas = maas;
    }
    
    // 💡 Çift Gönderme (Double Dispatch): Kendi tipini Ziyaretçi'ye bildirir.
    kabulEt(visitor) {
        visitor.ziyaretEtYonetici(this);
    }
}

// 4. Ziyaretçi Arayüzü
class KurumsalZiyaretci {
    ziyaretEtCalisan(calisan) { throw new Error("Uygulanmalı."); }
    ziyaretEtYonetici(yonetici) { throw new Error("Uygulanmalı."); }
}

// 5. Somut Ziyaretçi A: Prim Hesaplama İşlemi
class PrimHesaplayici extends KurumsalZiyaretci {
    ziyaretEtCalisan(calisan) {
        // Çalışanlar için prim: Maaşın %5'i
        const prim = calisan.maas * 0.05;
        console.log(`[PRİM] Çalışan ${calisan.ad}: ${prim} TL Prim`);
        return prim;
    }

    ziyaretEtYonetici(yonetici) {
        // Yöneticiler için prim: Maaşın %10'u
        const prim = yonetici.maas * 0.10;
        console.log(`[PRİM] Yönetici ${yonetici.ad}: ${prim} TL Prim (Yüksek Oran)`);
        return prim;
    }
}

// 6. İstemci Kodu (Client Code)

// Nesne Yapısı (Elementler)
const sirketYapisi = [
    new Calisan("Ali", 50000),
    new Yonetici("Veli", 150000),
    new Calisan("Ayşe", 60000),
];

// Yeni bir Ziyaretçi (İşlem) yaratılır
const primHesaplayici = new PrimHesaplayici();
let toplamPrim = 0;

console.log("--- Prim Hesaplama İşlemi (Element Sınıfları Değişmedi) ---");

// İstemci, sadece Element'in 'kabulEt' metodunu çağırır.
sirketYapisi.forEach(element => {
    // Element, Ziyaretçiyi kabul eder ve kendi tipine uygun metodu çağırmasını sağlar.
    element.kabulEt(primHesaplayici);
});

// Ziyaretçi Sınıfı Değişmeden Yeni İşlem Ekleme (OCP İlkesi)

class MaasRaporlayici extends KurumsalZiyaretci {
    ziyaretEtCalisan(calisan) {
        console.log(`[RAPOR] Çalışan: ${calisan.ad}, Brüt Maaş: ${calisan.maas} TL`);
    }

    ziyaretEtYonetici(yonetici) {
        console.log(`[RAPOR] YÖNETİCİ: ${yonetici.ad}, Brüt Maaş: ${yonetici.maas} TL`);
    }
}

console.log("\n--- Yeni İşlem: Maaş Raporlama ---");
const raporlayici = new MaasRaporlayici();
sirketYapisi.forEach(element => {
    element.kabulEt(raporlayici);
});

/*
Çıktı:
--- Prim Hesaplama İşlemi (Element Sınıfları Değişmedi) ---
[PRİM] Çalışan Ali: 2500 TL Prim
[PRİM] Yönetici Veli: 15000 TL Prim (Yüksek Oran)
[PRİM] Çalışan Ayşe: 3000 TL Prim

--- Yeni İşlem: Maaş Raporlama ---
[RAPOR] Çalışan: Ali, Brüt Maaş: 50000 TL
[RAPOR] YÖNETİCİ: Veli, Brüt Maaş: 150000 TL
[RAPOR] Çalışan: Ayşe, Brüt Maaş: 60000 TL
*/
        

🧭 Opsiyonel Okuma Notu

Bilgilendirme: Bu bölüm, konuların arka planına ve düşünsel temellerine daha derin bir bakış sunmak amacıyla hazırlanmıştır.

  • Matematiksel, tarihsel ve felsefî içerikler isteğe bağlı olarak okunabilir.
  • Her bölümün içerik seviyesi ve yoğunluğu farklılık gösterebilir.
  • Temel düzey kullanıcılar için zorunlu değildir, ileri düzey okuma niteliğindedir.
JavaScript'te Tasarım Desenleri

Tasarım Desenleri Tarihi , Felsefi ve Matematiksel Yaklaşımı

Tasarım desenleri, JavaScript'te kod yapısını daha modüler, okunaklı ve bakımı kolay hale getirmek için kullanılan desenlerdir.
Biz de bu bölümde tasarım desenlerinin tarihi, felsefi ve matematiksel yaklaşımını inceleyeceğiz.

Ana Konu Felsefi ve Tarihsel Açıklama

Desen (Pattern) Mimari Bilgeliğin Tanımı , Amacı ve Matematiksel Yaklaşımı

Desen Kavramının Tanımı ve Felsefi Çekirdeği

Desen (Pattern), yazılım mimarisi bağlamında, belirli bir bağlamda sıkça karşılaşılan bir soruna sunulan; kanıtlanmış, yeniden kullanılabilir ve iyi tanımlanmış bir çözüm dilidir.

Bir desen, sadece statik bir kod parçası veya basit bir algoritma değil; binlerce mühendisin on yıllar boyunca edindiği deneyimin damıtılmış bilgisidir.

Tarihsel Köken: Bu kavramın temelleri, bilgisayar bilimlerinden çok önce mimaride ( Christopher Alexander ) atılmıştır. Fiziksel bir mimari desen, bir insan ihtiyacını ( örneğin ışığın bir odaya en verimli girişi ) çözen ve farklı coğrafyalarda tekrar uygulanabilen başarılı bir tasarımsal yanıttır.

Evrensel Kural ve Mimari Bilgelik

Bir desenin bilimsel olarak var olabilmesi için üç zorunlu koşulun ( The Pattern Triad ) kesişimi şarttır:

1. Sıkça Tekrarlayan Bir Sorun | 2. Kanıtlanmış, Etkili Bir Çözüm | 3. Çözümün Uygulanacağı Belirli Bir Bağlam.

Yazılım dünyasında desen kullanmak, tekerleği yeniden icat etmek yerine, yüzlerce mühendisin yıllar içinde oluşturduğu o devasa kural kitabını uygulamak ve kolektif bir bilgeliğe ortak olmak anlamına gelir.

Programlamadaki Stratejik Etkisi

Tasarım desenlerinin temel amacı teknik bir çözüm sunmanın ötesinde, projenin sürdürülebilirlik ( maintainability ) ve iletişim ( communication ) kalitesini yükseltmektir.

Paylaşılan Söz Varlığı (Shared Vocabulary): Desenler, geliştiricilerin karmaşık mimari fikirleri "Singleton" veya "Observer" gibi tek bir terimle hızla aktarmasını sağlar. Bu ortak dil, ekip içi iletişimi ışık hızına çıkarır ve kod inceleme süreçlerini şeffaflaştırır.

Esneklik ve Sağlamlık (Resilience): İyi desenlenmiş bir sistemde bir gereksinim değiştiğinde, bu değişim sistemin tamamını sarsmaz; sadece o desenin belirli bir katmanında çözülür. Bu, geleceğe yönelik bir önleyici mimari oluşturulmasına yardımcı olur.

Matematiksel Yaklaşım Giriş

Tasarım desenleri, yüzeyde yazılım mühendisliğine ait görünse de; özünde doğanın ve matematiğin karmaşıklığı yönetme biçiminden türemiştir.

Matematiksel olarak desen; tekrar eden bir probleme uygulanan, belirli bir mantıksal düzeni takip eden yinelenen (recursive) bir fonksiyon gibidir. Bu tekrar rastgele değil, sistemin entropisini düşürmeye yönelik bir düzen arayışıdır.

Tanım, Özellikler ve Sınıflandırma Genel Bilgi

Mimari Taksonomi: Çözüm Odaklı Kategorizasyon

Tasarım Desenleri, yazılım geliştirme sürecinde karşılaşılan problemlerin doğasına göre belirli kategorilere ayrılarak sınıflandırılır. Bu taksonomi, bir geliştiricinin elindeki sorunu teşhis etmesini ve uygun "tedavi yöntemini" yani doğru deseni hızla seçmesini sağlar.

Desenlerin nihai hedefi, sadece kodun yazım şeklini değil; kodun üstlendiği sorumlulukları ve nesnelerin birbirleriyle kurduğu etkileşim trafiğini evrensel standartlara bağlamaktır.

Ortak Dil ve İletişim Verimliliği

Bu kategorizasyon, mühendisler arasında "Paylaşılan Söz Varlığı" ( Shared Vocabulary ) oluşturur. Binlerce satırlık mimari bir kurguyu anlatmak yerine, sadece bir kategori ismi veya desen adı kullanarak ( örneğin "Burada bir Yapısal Desen kullanmalıyız" diyerek ) devasa fikirlerin saniyeler içinde iletilmesine imkan tanır.

Arama Alanını Daraltma: Bir tasarım problemi baş gösterdiğinde, bu sınıflandırma sistemi çözüm arama alanını mantıksal olarak daraltır. Eğer sorun nesne yaratımıyla ilgiliyse Oluşturucu Desenlere, sistem parçalarının birleşimiyle ilgiliyse Yapısal Desenlere, nesne iletişimiyle ilgiliyse Davranışsal Desenlere odaklanılması gerektiğini netleştirir.

Desenlerin Ortak Karakteristik Özellikleri

Hangi sınıfa ait olursa olsun, profesyonel bir tasarım deseni şu üç temel özelliği bünyesinde barındırmalıdır:

Esneklik: Kodun yeni gereksinimlere direnç göstermeden genişleyebilmesini sağlar.

Soyutlama: Karmaşık iç mantığı gizleyerek kullanımı kolay ve standart bir dış yüzey sunar.

Yeniden Kullanılabilirlik: Bir projede üretilen mimari aklın, başka bir projede de aynı güvenilirlikle çalışmasını garanti eder.

Özetle bu sınıflandırma, yazılım mimarisini bir "deneme-yanılma" süreci olmaktan çıkarıp, sistematik ve bilimsel bir "mühendislik disiplinine" dönüştürür.

Desen (Pattern) Yazılımın Tarihsel Kökeni Christopher Alexander ve Mimari Mirası

Alexander'ın Felsefesi: Yaşanabilirlik ve Sorunların Tekrarı

Mimari ve şehir planlamasının öncü ismi Christopher Alexander, insanların kendilerini rahat, güvende ve canlı hissettikleri mekanların tesadüfen değil, belirli ve tekrar eden yapısal çözümler sayesinde var olduğunu gözlemledi.

Alexander’a göre bir tasarım hatası, bir kerelik talihsiz bir olay değil; temelde yatan derin bir kuvvetler çatışmasının ( conflict of forces ) kaçınılmaz bir sonucuydu.

Kuvvetler Çatışması ve İdeal Denge

Bir desenin var olma nedeni, zıt kuvvetleri bir dengede buluşturmaktır.

Örnek: Bir pencerenin büyük olması istenir ( doğal ışık ihtiyacı ), ancak bu durum enerji kaybını artırır ( ısı yalıtımı sorunu ). Desenin asıl işlevi, bu iki zıt kuvvet arasındaki ideal dengeyi kuran o evrensel mimari çözümü sunmaktır.

Alexander, 1977 yılında yayımladığı "A Pattern Language" adlı eserinde, bu tür çatışmaları çözen 253 farklı mimari deseni kataloglayarak tasarım dünyasında yeni bir çağ açmıştır.

Desenlerin Yapısı: Bir Dil İnşa Etmek

Alexander’a göre desenler sadece sonuçla ilgilenmez; çözüme giden mantıksal yolu da kodlar. Bir mimari desen, yazılım mühendisliğine miras kalacak üç temel sacayağından oluşur:

1. Bağlam (Context): Desenin hangi koşullar altında uygulanacağını belirleyen çevresel faktörler.

2. Sorun (Problem): Çatışan kuvvetlerin tanımlandığı ve çözüm bekleyen ana zorluk.

3. Çözüm (Solution): Çatışmayı sonlandıran ve dengeyi sağlayan soyut yapısal model.

Yazılım Dünyasına Uzanan Köprü

1980’lerin sonunda yazılım mühendisleri, büyük ölçekli dijital sistemlerde de mimari projelerdekine benzer yapısal krizlerin tekrar ettiğini fark ettiler.

Alexander’ın metodolojisi; karmaşık yazılım problemlerine sistematik bir kataloglama yaklaşımı getirilebileceği, yazılımın da kendi "Desen Dili" ( Pattern Language ) üzerinden inşa edilebileceği fikrine ilham kaynağı olmuştur.

Bu tarihsel miras, yazılımın zanaattan mühendisliğe evrilmesindeki en kritik dönüm noktalarından biridir.

Kavramsal Mantık Desen ve Tekrarın Matematiksel Yeri

Fraktal Düzen: Kaostan Mimariye Geçiş

Tasarım Desenleri, yazılım evreninde tekrar eden bir soruna uygulanan, matematiksel olarak optimize edilmiş ve doğruluğu ispatlanmış bir çözüm kümesidir.

Buradaki tekrar kavramı, basit bir "kopyala-yapıştır" mekanizmasından ziyade; doğada, fraktallarda ve saf matematikte bulunan o derin, öz-benzerlik taşıyan mantıksal düzeni yansıtır. Yazılım mühendisliğinde bu düzen, kontrolsüz büyüyen sistemlerin doğal eğilimi olan entropiye (kaosa) karşı bir savunma hattı oluşturmak için hayati önem taşır.

Zıt Kuvvetler ve Matematiksel Denge

Desenler, çözümleri kısıtlayıcı bir dille formalize ederek, problemin doğasında var olan zıt kuvvetler ( hız vs. bellek, esneklik vs. karmaşıklık gibi ) arasındaki ideal denge noktasını bulmayı hedefler.

Matematiksel Stabilite: Bu düzen, kodun sadece anlık olarak çalışmasını değil; aynı zamanda öngörülebilir ve sürdürülebilir bir yapıda kalmasını garanti eder. Bir desen uygulamak, sisteme matematiksel bir değişmez ( invariant ) kazandırmak demektir; yani girdi veya çevre değişse de sistemin mimari bütünlüğü bu temel üzerine korunur.

Mühendislik Çıkarımı: Öngörülebilir Gelecek

Yazılımda desenlerin sağladığı bu kavramsal temel, mimari ilkelerin ( SOLID, KISS, DRY ) rastgele kurallar değil, sistemin toplam bilişsel yükünü azaltmaya yönelik matematiksel birer optimizasyon olduğunu kanıtlar.

Sonuç olarak desenler, yazılımı bir sanat formu olmaktan çıkarıp; her bir parçanın neden-sonuç ilişkisiyle birbirine bağlandığı, yüksek hassasiyetli bir matematiksel makineye dönüştürür.

Tekrar ve Ölçek İlintisi Fraktal Geometri

Doğanın Matematiği: Karmaşıklığın Altındaki Düzen

Desen kavramı, matematikteki en somut ve büyüleyici karşılığını Fraktal Geometri'de bulur. Fraktallar; kar taneleri, ağaç dalları veya nehir yatakları gibi doğada düzensiz ve kaotik görünen yapıların arkasındaki gizli, sistematik ve matematiksel düzeni inceler.

Öz Benzerlik (Self-Similarity): Bir fraktalın en karakteristik özelliği, yapının her ölçekte kendine benzemesidir. Yapının en küçük hücresi, aslında büyük resmin tamamının genetik kodunu ve yapısal özelliklerini taşır. Bir ağacın en uçtaki dalı ile ana gövdesinin formu aynı matematiksel kurala ( algoritmaya ) göre şekillenir.

Yazılım Mimarisinde Fraktal Yaklaşım

Modern ve sürdürülebilir bir yazılım mimarisinden beklenen en temel nitelik, bu ölçekten bağımsızlık durumudur. Fraktal mantık, yazılımdaki temel tasarım prensiplerinin ( Gevşek Bağlılık, Tek Sorumluluk ) sadece genel mimaride değil, en küçük fonksiyon seviyesinde bile tutarlı bir şekilde tekrarlanmasını şart koşar.

Mimari Tutarlılık: Karmaşık bir alt sistemi yöneten bir Facade deseninin sağladığı disiplin, o sistemin içindeki algoritmaları yöneten Strategy deseniyle aynı mimari ahlakı yansıtmalıdır. Bir geliştirici, sistemin mikro bir parçasını anladığında, bu yapısal zekanın makro ölçekte de geçerli olacağını bilerek güvenle ilerler.

Operasyonel Güç: Öngörülebilirlik ve Ölçekleme

Bakım ve Genişletilebilirlik: Fraktal yapıya sahip bir sistemde, yeni bir özellik eklemek veya bir hatayı ayıklamak ( debugging ) çok daha basittir. Çünkü kodun nerede aranacağı ve hangi kurala uyacağı, sistemin her katmanında öngörülebilir bir matematiksel düzen içindedir.

Sonuç olarak, yazılım mimarisinde fraktal tutarlılığı yakalamak; sistemi rastgele büyüyen bir yığın olmaktan çıkarıp, her hücresiyle bütünün amacına hizmet eden sağlam (robust) ve sonsuza dek ölçeklenebilir bir organizmaya dönüştürür.

Soyutlama ve Küme Tanım Küme Teorisi (Set Theory)

Mantıksal Tanım: Kümelerin ve Sözleşmelerin Rolü

Tasarım Desenleri, bir programlama dili içindeki somut ( concrete ) nesneler üzerinde yükselen, ancak onlardan bağımsız olan soyut çözümlerdir. Bu soyutlama yeteneği, desenin asıl gücü olup mantıksal olarak Küme Teorisi ( Set Theory ) prensipleriyle açıklanır.

Küme (The Set): Küme teorisi perspektifinden, bir desen ( örneğin Factory Method ), belirli bir problemi çözmek için bir araya gelmesi gereken sınıflar kümesini ( Set of Classes ) ve bu sınıfların birbirleriyle kuracağı matematiksel ilişki kurallarını tanımlar. Desen, aslında bu kümeye ait olmanın "giriş şartlarını" belirleyen üst yapıdır.

Küme Üyeliği: Somut sınıflar, ancak desende tanımlanan kurallara ve arayüze ( interface ) harfiyen uyduklarında bu kümenin geçerli bir üyesi ( member ) olabilirler. Bu üyelik, tüm nesnelerin ortak bir fonksiyonu ( Product veya Creator arayüzü gibi ) yerine getireceğini kesin olarak garanti eder.

Kısıtlama ve Matematiksel Sözleşme

Desenin kendisi, bu kümenin üyelerinin hangi işlemleri gerçekleştirmesi gerektiğini mantıksal olarak kısıtlar. Bu durum, desenin sadece bir kod dizisi değil; nesneler arası sözleşmeleri ve mantıksal bariyerleri de kodladığı anlamına gelir.

Sağlamlık (Robustness): Desenin sağladığı bu matematiksel kısıtlama, kodu kullanan tarafın ( istemci/client ) arka planda hangi somut sınıfın çalıştığını bilme zorunluluğunu ortadan kaldırır. İstemci, sadece kümenin kuralına uyulduğu sürece ( yani standart metodun varlığına güvenerek ) güvenle işlem yapabilir.

Mantıksal Bütünlük ve Esneklik

Küme teorisi temelli bu yaklaşım, sisteme sınırsız sayıda farklı somutlaştırma ( yeni üyeler ) eklenmesine izin verirken, sistemin genel mantıksal bütünlüğünü sarsılmaz bir koruma altına alır.

Sonuç olarak desenler, yazılımı "nesnelerin rastgele topluluğu" olmaktan çıkarıp, her bir parçasının ortak bir matematiksel sözleşmeye bağlı olduğu "mantıksal bir küme hiyerarşisine" dönüştürür.

Gevşek Bağlılık ve İlişkisel Mantık Bağımlılıklar ve İlişkiler

Bağımlılık Yönetimi: Soyut Cebir ve İlişkisel Düzen

Tasarım Desenleri, nesneler arası ilişkileri yönetirken soyut cebirdeki ilişkisel mantığı referans alır. Bu yaklaşımın temel hedefi, sistemin parçaları arasındaki bilgi alışverişini minimum düzeye indirerek her bileşeni kendi içinde özgürleştirmektir.

Bağımsızlık Mimarisi: Gevşek bağlılık, bir bileşenin, etkileşime girdiği diğer bileşenlerin iç dünyasından ( somut sınıf isimleri, değişken detayları ) tamamen yalıtılmış olması demektir. Bağımlılık, katı bir sınıfa değil, esnek bir arayüze (sözleşmeye) dayandırılır. Bu sayede sistem parçaları, bir Lego bloğu gibi kolayca birbirinin yerine ikame edilebilir ( pluggable ) hale gelir.

Matematiksel Fonksiyon Olarak Kod: Öngörülebilirlik

Bir deseni uygulamak, aslında kodun belirli bir girdiye karşılık beklenen çıktıyı üreten soyut bir matematiksel fonksiyona uymasını sağlamaktır.

Mantıksal Tutarlılık: Bu yaklaşım, sistemin her bir parçasının, içinde bulunduğu bağlam ne kadar karmaşık olursa olsun, aynı girdiye karşı her zaman kısıtlanmış ve öngörülebilir bir tepki vereceğini garanti eder. Bu durum, yazılımın tesadüfi sonuçlar üretmesini engelleyerek deterministik bir yapı kurulmasını sağlar.

Kısıtlanmış Sistem ve Mimari Sağlamlık

Net Sınırlar: Bir desen, bir bileşenin ne kadar bilgi paylaşabileceği ve hangi sorumlulukları üstlenebileceği konusunda net sınırlar çizer. Bu disiplinli kısıtlama, sistemin kaotik ve kontrolsüz büyümesini ( spaghetti architecture ) engelleyen en güçlü mimari bariyerdir.

Sonuç olarak, gevşek bağlılık sadece bir "kolaylık" değil; yazılımın değişim dalgalarına karşı ayakta kalmasını sağlayan, parçaların birbirini kırmadan esnemesine izin veren mantıksal bir denge sistemidir.

Yazılımdaki Doğuş Gang of Four (GoF) ve Amacı

Felsefi Geçiş: Alexander'dan OOP Formalizasyonuna

Tasarım Desenleri kavramının yazılım mühendisliğinde bir disiplin olarak resmileşmesi, 1994 yılında yayımlanan "Design Patterns: Elements of Reusable Object-Oriented Software" adlı çığır açan kitapla gerçekleşmiştir.

Kitabın yazarları olan Erich Gamma, Richard Helm, Ralph Johnson ve John Vlissides, yazılım dünyasında efsanevi "Gang of Four" (GoF) yani "Dörtlü Çete" olarak anılmaktadır.

Tercüme ve Kataloglama: GoF'un temel vizyonu, Christopher Alexander'ın fiziksel mimarideki "desen dili" felsefesini, Nesne Yönelimli Programlama ( OOP ) dünyasına tercüme etmekti. 1990'ların karmaşıklaşan sistemlerinde mühendislerin sürekli "tekerleği yeniden icat ettiğini" fark eden ekip, bu kaosu bir kural kitabına dönüştürdü.

Stratejik Amaç: Kanıtlanmış Bilgelik

23 Temel Tasarım: GoF, deneyimli geliştiricilerin karşılaştığı sorunlara yönelik 23 evrensel çözümü belirledi ve bunları standardize etti. Bu desenler teorik varsayımlar değil; gerçek dünyadaki devasa projelerde başarısı onaylanmış en iyi uygulamalardır ( best practices ).

Bu kataloğun temel hedefi; kodu daha esnek, tekrar kullanılabilir ve bakımı kolay ( maintainable ) bir yapıya kavuşturarak yazılım mühendisliğine kanıtlanmış bir bilgelik sunmaktır.

Mimari Etki: Ortak Söz Varlığı (Shared Vocabulary)

GoF'un teknoloji dünyasına en büyük armağanı, teknik bir çözümden öte evrensel bir iletişim dili yaratmasıdır:

Hız ve Netlik: Bir ekip arkadaşınıza "Burada bir Singleton kullanmalıyız" dediğinizde, sayfalarca sürecek "tek nesne örneği, global erişim, kontrol mekanizması" açıklamasını tek bir kelimeye sığdırmış olursunuz. Bu, tasarım tartışmalarını ışık hızına çıkarır.

Sistematik Sınıflandırma: Desenleri Oluşturucu, Yapısal ve Davranışsal olarak üç ana kampa ayırarak, bir problemin doğasına göre çözüm arama alanını mantıksal bir düzene oturttular.

Sonuç olarak Gang of Four, yazılım geliştirmeyi bir "zanaat" olmaktan çıkarıp, prensipleri ve terminolojisi olan bilimsel bir mühendislik dalına dönüştürmüştür.

GoF Desenlerinin Sınıflandırma Mantığı Oluşturucu, Yapısal ve Davranışsal

Stratejik Matris: Amaç ve Kapsam Ekseni

Gang of Four (GoF), katalogladıkları 23 deseni kategorize ederken rastgele bir sıralama yerine; sorunlara yaklaşım tarzlarını belirleyen iki ana eksenli sistematik bir matris kullanmıştır: Amaç (Purpose) ve Kapsam (Scope).

1. Amaç (Purpose): Desenin ne yaptığına odaklanır. Nesnelerin nasıl yaratıldığı, nasıl bir araya getirildiği veya nasıl etkileşime girdiği bu eksende tanımlanır.

2. Kapsam (Scope): Desenin uygulama düzlemini belirler. Desen sınıflar arasındaki statik ( kalıtım temelli ) ilişkilerle mi, yoksa nesneler arasındaki dinamik ( nesne temelli ) ilişkilerle mi ilgileniyor?

Mimari Karar Verme Sürecini Hızlandırma

Bu matris temelli yaklaşım, deneyimli geliştiriciler için "doğru çözümü nerede aramalıyım?" sorusunu sistematik bir sürece dönüştürür. Bir problemle karşılaşıldığında, sorunun doğasını bu iki eksene yerleştirmek, çözüm arama alanını anında daraltır.

Eğer sorun nesne oluşturma maliyetiyse Oluşturucu, parçaların montajıysa Yapısal, görev dağılımıysa Davranışsal desenler kümesine odaklanılması gerektiğini netleştirir.

Felsefeden Uygulamaya: Ekip İçi İletişim

Sınıflandırma mantığı, bir mimari kararın hem felsefesini hem de uygulama düzlemini şeffaflaştırır. Bu durum, geliştirme ekipleri içinde iletişim hızını artırırken, tasarım aşamasında yapılan tartışmaların teknik bir temel üzerinde yürümesini sağlar.

Sonuç olarak GoF sınıflandırması, yazılım mimarisini bir tahmin oyunu olmaktan çıkarıp; sorunların ve çözümlerin belirli bir koordinat sisteminde yer aldığı disiplinli bir mühendislik haritasına dönüştürmüştür.

Kapsam Ekseni (Scope) Nasıl Uygulanır?

Uygulama Seviyesi: Statik ve Dinamik İlişkiler

Kapsam Ekseni, bir tasarım desenindeki ana etkileşimin sınıfların kalıtımına mı ( inheritance ) yoksa nesnelerin çalışma zamanı bileşimine mi ( composition ) dayandığını belirleyen temel ölçeklendirme kriteridir.

Bu eksen, bir desenin sistemdeki esnekliğini, genişleyebilirliğini ve değişim yeteneğini belirleyen en kritik faktördür. Temel olarak, yazılımın yapısını belirleyen ilişkilerin statik mi yoksa dinamik mi olacağına karar verir.

Mimari Karar: Derleme mi, Çalışma Zamanı mı?

Sınıf Kapsamı (Class Scope): Bu seviyedeki desenler, nesneler arasındaki ilişkileri kalıtım yoluyla düzenler. İlişkiler derleme zamanında ( compile-time ) sabitlenir. Bu durum yapısal bir sağlamlık sunsa da, çalışma anında davranışı değiştirmeyi zorlaştırır.

Nesne Kapsamı (Object Scope): Nesneler arasındaki ilişkileri bileşim ( composition ) yoluyla kurar. İlişkiler dinamiktir ve uygulamanın çalıştığı anda ( run-time ) değiştirilebilir. Bu, sisteme olağanüstü bir esneklik kazandırır.

GoF Stratejisi: Nesne Bileşimine Yönelim

Gang of Four'un katalogladığı 23 desenin büyük bir çoğunluğu, modern nesne yönelimli programlama ( OOP ) eğilimlerine uyarak Nesne Kapsamı modelini tercih eder.

Mühendislik Çıkarımı: "Kalıtım yerine bileşimi tercih et" ilkesi, desenlerin bu eksende neden çoğunlukla dinamik tarafta yer aldığını açıklar. Bu sayede, kod parçaları birbirine sıkı sıkıya kaynatılmak yerine, çalışma zamanında ihtiyaç duyulduğunda birleştirilen tak-çıkar modüller haline gelir.

Sonuç olarak Kapsam Ekseni, yazılım mimarının sistemdeki "katılık" ve "esneklik" oranını belirlediği, kodun yaşam döngüsünü kontrol eden bir strateji düzlemidir.

Sınıf Desenleri (Class Patterns) Sınıf Yaratma ve Yönetimi

Odak: Kalıtım ve Statik Yapı

Sınıf Desenleri, nesnelerden ziyade sınıflar arasındaki ilişkileri merkeze alan ve bu hiyerarşiyi kalıtım ( extends, implements ) mekanizmaları üzerinden kuran yapılardır.

Bu desenlerin temel uzmanlık alanı, bir sınıfın sahip olduğu sorumlulukların, yeteneklerin ve karar verme yetkilerinin alt sınıflara ( subclasses ) nasıl devredileceğini ( delegation ) mimari olarak belirlemektir.

Mekanizma: Derleme Zamanı Disiplini

Sınıf desenleri, karakteristik olarak derleme zamanında ( compile-time ) şekillenir. Bu, desenin kurduğu bağların ve yapısal kararların, uygulama ayağa kalktıktan sonra ( run-time ) değişmeyeceği anlamına gelir.

Mimari Sabitlik: Bir sınıf bu deseni uyguladığında, kurulan yapısal iskelet uygulama yaşam döngüsü boyunca sarsılmaz bir kararlılıkla korunur. Örneğin, Factory Method deseninin sınıf tabanlı versiyonunda; hangi somut nesnenin üretileceğine kalıtım zincirindeki bir alt sınıf karar verir ve bu kural mimarinin değişmez bir parçası haline gelir.

Kritik Örnekler ve Uygulama Alanları

Uygulama Modelleri: Sınıf desenleri, özellikle sistemin ana omurgasını oluştururken tercih edilir. En yaygın örnekleri arasında; nesne üretim mantığını alt sınıflara bırakan Factory Method'un sınıf versiyonları ve iki uyumsuz arayüzü kalıtım yoluyla birleştiren Adapter deseninin sınıf versiyonları yer alır.

Sonuç olarak Sınıf Desenleri, yazılımın "genetik kodunu" belirleyen; esnekliği çalışma zamanında değil, hiyerarşik yapılandırma aşamasında arayan, güvenilir ve sağlam bir mimari temel sunar.

Nesne Desenleri (Object Patterns) Nesne Yaratma ve Yönetimi

Odak: Nesne Bileşimi ve Dinamik İlişkiler

Nesne Desenleri, sınıfların katı kalıtım hiyerarşilerinden ziyade, nesnelerin birbirleriyle nasıl bir araya geldiğine ( composition ) ve çalışma zamanındaki ( run-time ) akışkan ilişkilerine odaklanır.

Yetki Devri (Delegation): Bu desenler, bir nesnenin tüm işi tek başına yapması yerine, başka bir nesneye referans tutarak belirli sorumlulukları o nesneye devretmesi esasına dayanır. Bu sayede bir nesne, içine hangi yardımcı nesneyi aldığına bağlı olarak tamamen farklı bir işlevsellik kazanabilir.

Mekanizma: Çalışma Zamanı Özgürlüğü

Nesne desenleri, karakteristik olarak çalışma anında şekillenir. Bu, kod derlenip çalışmaya başladıktan sonra bile nesnelerin birbirleriyle olan bağlarının koparılabileceği, değiştirilebileceği veya yeniden yapılandırılabileceği anlamına gelir.

Mimari Esneklik: GoF kataloğundaki 23 desenin neredeyse tamamına yakını (%95'i) bu kategoriye girer. Bunun temel nedeni, "Kalıtım yerine Bileşimi tercih et" ( Favor Composition over Inheritance ) felsefesinin, değişime en dirençli ve en esnek yapıları sunmasıdır.

Uygulama Alanları ve Kritik Örnekler

Nesne desenleri, sistemin yaşayan ve değişen kısımlarını yönetmek için mükemmeldir. Örneğin; bir nesneye çalışma anında dinamik olarak yeni özellikler ekleyen Decorator, isteği işleyebilecek nesneler arasında bağ kuran Chain of Responsibility veya algoritmaları nesneleştirip birbirinin yerine kullanılabilir kılan Strategy bu ekolün en güçlü temsilcileridir.

Sonuç olarak Nesne Desenleri, yazılımı "katı ve kırılgan" bir yapıdan kurtarıp, çalışma zamanında ihtiyaca göre şekil alabilen "akıllı ve modüler" bir sisteme dönüştüren temel mühendislik araçlarıdır.

Öğrenme Yolu

JavaScript öğrenme yolculuğunuzda neredesiniz?

İlerleme
100%
17 Tamamlandı 18 Toplam
Giriş sayfası dahil edilmedi

Bu bölüm, JavaScript öğrenme yolculuğunuzdaki ilerlemenizi görselleştirir. Aşağıda göreceğiniz adımlar, konular arasındaki mantıksal sıralamayı ve öğrenme akışını temsil eder. Tamamlanan konular mavi tonlarda gösterilir ve üzerinde bir onay işareti bulunur. Aktif konu, şu anda üzerinde çalıştığınız bölümdür ve parlak mavi renkle vurgulanır. Sonraki adımlar ise henüz tamamlanmamış konuları gösterir ve daha soluk tonlarda görüntülenir.

Her adım arasındaki oklar, öğrenme sırasını ve konular arasındaki bağlantıyı gösterir. Bu yapı, hangi konuları tamamladığınızı, hangi konuda olduğunuzu ve sıradaki adımlarınızı net bir şekilde görmenizi sağlar.

Tamamlandı 1

JavaScript Giriş

JavaScript'e giriş ve temel kavramlar

Tamamlandı 2

Değişkenler

var, let, const ve scope kavramları

Tamamlandı 3

Veri Tipleri

JavaScript'te temel veri tipleri ve kullanımları

Tamamlandı 4

Operatörler

Aritmetik, mantıksal ve karşılaştırma operatörleri

Tamamlandı 5

If-Else

Koşullu yürütme ve karar yapıları

Tamamlandı 6

Switch-Case

Çoklu koşul kontrolü ve case yapısı

Tamamlandı 7

While

While ve Do-While döngüleri

Tamamlandı 8

For

For, For...of ve For...in döngüleri

Tamamlandı 9

Diziler (Arrays)

Dizi oluşturma, manipülasyon ve metodları

Tamamlandı 10

Functions

Fonksiyon tanımlama, parametreler ve return

Tamamlandı 11

Objects

Nesne oluşturma, özellikler ve metodlar

Tamamlandı 12

DOM

Document Object Model ve DOM manipülasyonu

Tamamlandı 13

Class

ES6 Class yapısı ve kalıtım

Tamamlandı 14

Modülerlik ve Kod Organizasyonu

ES Modülleri, Bağımlılık Enjeksiyonu ve IoC Konteynerleri

Tamamlandı 15

Performance ve Memory

Performans optimizasyonu ve bellek yönetimi

Tamamlandı 16

Asenkron Programlama

Promise, async/await ve JSON işlemleri

Tamamlandı 17

Mimari Prensipler ve Desenler

Yazılım mimarisi prensipleri ve desenleri

Tamamlandı 18

Tasarım Desenleri

Creational, Structural ve Behavioral desenler