Creational (Oluşturucu), Structural (Yapısal) ve Behavioral (Davranışsal) Tasarım Desenleri

Tasarım desenleri, yazılım mühendisliğinde yaygın olarak karşılaşılan problemleri çözmek ve tekrar kullanılabilir, esnek ve sürdürülebilir kod tasarlamak için kullanılan önceden belirlenmiş ve kanıtlanmış çözümlerdir. Bu desenler, belirli bir yapı ve düzen içinde, belirli bir durum veya görev için en iyi uygulamaları sağlayarak yazılım geliştirme süreçlerini kolaylaştırır.

Tasarım desenleri, kategorilere göre sınıflandırılabilir. Genellikle üç ana kategori altında toplanırlar:

  1. Creational (Yaratıcı) Desenler: Nesnelerin yaratılmasını ve örneklenmesini ele alır. Bu desenler, nesnelerin nasıl oluşturulacağı, inşa edileceği ve temsil edileceği üzerine odaklanır. Örnekler arasında Singleton, Factory, Prototype, ve Builder desenleri yer alır.

  2. Structural (Yapısal) Desenler: Nesnelerin birbirleriyle nasıl bağlandığını ve birleştirildiğini ele alır. Bu desenler, sınıfların veya nesnelerin bileşenlerinin nasıl düzenlendiği ve yapılandırıldığıyla ilgilenir. Örnekler arasında Adapter, Bridge, Composite, Decorator, Proxy, ve Facade desenleri yer alır.

  3. Behavioral (Davranışsal) Desenler: Nesnelerin davranışlarını ve işbirliğini ele alır. Bu desenler, nesnelerin nasıl iletişim kurduğu ve işbirliği içinde çalıştığı konusuna odaklanır. Örnekler arasında Observer, Strategy, Template, Visitor, Command, Chain of Responsibility, ve Interpreter desenleri yer alır.

Tasarım desenleri, yazılım geliştirme sürecinde kodun yeniden kullanılabilir, esnek ve sürdürülebilir olmasını sağlayarak tasarım ve implementasyon karmaşıklığını azaltır. Tasarım desenlerinin kullanılması, yazılım projelerinin daha iyi organizasyonunu ve bakımını sağlayarak geliştirme süreçlerini daha verimli hale getirir. Ancak, tasarım desenleri her durumda uygun değildir ve dikkatli bir değerlendirme ve anlayış gerektirir.

— Creational (Oluşturucu) Tasarım Desenleri

     • Naïve (Basit) Singleton Tasarım Deseni

     • Thread-safe Singleton Tasarım Deseni

     • Factory Tasarım Deseni

     • Abstract Factory Tasarım Deseni

     • Builder Tasarım Deseni

     • Prototype Tasarım Deseni

Structural (Yapısal) Tasarım Desenleri

     • Adapter Tasarım Deseni

     • Bridge Tasarım Deseni

     • Composite Tasarım Deseni

     • Decorator Tasarım Deseni

     • Facade Tasarım Deseni

     • Flyweight Tasarım Deseni

     • Proxy Tasarım Deseni

Behavioral (Davranışsal) Tasarım Desenleri

     • Chain of Responsibility Tasarım Deseni

     • Command Tasarım Deseni

     • Interpreter Tasarım Deseni

     • Iterator Tasarım Deseni

     • Mediator Tasarım Deseni

     • Memento Tasarım Deseni

     • Observer Tasarım Deseni

     • State Tasarım Deseni

     • Strategy Tasarım Deseni

     • Template Tasarım Deseni

     • Visitor Tasarım Deseni

Creational (Oluşturucu) Tasarım Desenleri

- Singleton Tasarım Deseni

Naïve (Basit) Singleton Tasarım Deseni

Bu yaklaşım, basitçe örneğin ilk çağrıldığı anda oluşturulacağı ve daha sonraki çağrılarda aynı örneğin döndürüleceği şekilde çalışır. Ancak, bu yöntem multithreaded ortamlarda sorunlara neden olabilir, çünkü birden fazla iş parçacığı aynı anda Singleton örneğini oluşturmaya çalışabilir. Bu nedenle, thread-safe bir Singleton örneği için daha sofistike bir yaklaşım gerekir.

public class NaiveSingleton
{
    // Adım 2: Singleton sınıfının örneğini depolamak için private static bir alan oluşturuyoruz.
    private static NaiveSingleton instance;

    // Adım 3: Constructor'ı private yapıyoruz.
    private NaiveSingleton()
    {
        // Singleton sınıfının dışarıdan oluşturulmasını önlemek için boş constructor.
    }

    // Adım 4: Yeni örneklerin oluşturulmasını engellemek ve mevcut örneği döndürmek için bir metot oluşturuyoruz.
    public static NaiveSingleton GetInstance()
    {
        // Eğer instance alanı null (boş) ise, yani daha önce hiç örnek oluşturulmamışsa, yeni bir örnek oluşturuyoruz.
        if (instance == null)
        {
            instance = new NaiveSingleton();
        }

        // Eğer daha önce oluşturulmuş bir örnek varsa, mevcut örneği döndürüyoruz.
        return instance;
    }

    // Singleton sınıfının diğer işlevlerini buraya ekleyebilirsiniz.
    // ...
}

Yukarıdaki kodda, NaiveSingleton adında basit bir Singleton sınıfı oluşturduk. Sınıfın constructor'ı private olduğundan, sınıf dışından doğrudan örnek oluşturulamaz. Bunun yerine, GetInstance adında bir static metot kullanarak Singleton örneğine erişim sağlamamız gerekiyor. Eğer daha önce hiç örnek oluşturulmamışsa, GetInstance metodu yeni bir örnek oluşturacak; aksi takdirde, daha önce oluşturulan örneği döndürecektir.

Ancak, bu yaklaşım, multithreaded bir ortamda iki veya daha fazla iş parçacığı aynı anda Singleton örneği oluşturmaya çalışırsa sorunlara neden olabilir. Bu nedenle, Thread-safe bir Singleton tasarım deseni tercih edilmelidir.

Thread-safe Singleton Tasarım Deseni

Thread-safe Singleton deseni, multithreaded ortamlarda birden fazla iş parçacığı tarafından aynı anda Singleton örneği oluşturulmasını engellemek için tasarlanmıştır. İşte thread-safe bir Singleton örneği:

public class ThreadSafeSingleton
{
    // Adım 2: Singleton sınıfının örneğini depolamak için private static bir alan oluşturuyoruz.
    private static ThreadSafeSingleton instance;

    // Adım 3: Constructor'ı private yapıyoruz.
    private ThreadSafeSingleton()
    {
        // Singleton sınıfının dışarıdan oluşturulmasını önlemek için boş constructor.
    }

    // Adım 4: Yeni örneklerin oluşturulmasını engellemek ve mevcut örneği döndürmek için bir metot oluşturuyoruz.
    public static ThreadSafeSingleton GetInstance()
    {
        // Eğer daha önce oluşturulmuş bir örnek varsa, mevcut örneği döndürüyoruz.
        if (instance != null)
        {
            return instance;
        }

        // Eğer instance alanı null (boş) ise, yani daha önce hiç örnek oluşturulmamışsa, kilitleme mekanizması ile yeni bir örnek oluşturuyoruz.
        lock (typeof(ThreadSafeSingleton))
        {
            if (instance == null)
            {
                instance = new ThreadSafeSingleton();
            }
        }

        return instance;
    }

    // Singleton sınıfının diğer işlevlerini buraya ekleyebilirsiniz.
    // ...
}

Yukarıdaki kodda, ThreadSafeSingleton adında thread-safe bir Singleton sınıfı oluşturduk. GetInstance metodu, birden çok iş parçacığı tarafından aynı anda çağrıldığında bile yalnızca bir kez örnek oluşturulmasını garanti etmek için lock anahtar kelimesini kullandık. Bu sayede, bir iş parçacığı Singleton örneğini oluşturduğunda, diğer iş parçacıkları beklemek zorunda kalacak ve birbirleriyle çakışmayacaktır.

Bu şekilde, thread-safe bir Singleton deseni, birden çok iş parçacığı tarafından kullanıldığında bile doğru çalışacaktır ve yalnızca bir kez örnek oluşturulacağı garanti edilecektir. Ancak, lock anahtar kelimesi performansı biraz etkileyebilir, bu nedenle uygulamanızın ihtiyaçlarına göre diğer thread-safe yöntemleri de düşünebilirsiniz (örn. Double-Checked Locking, Lazy Initialization vb.).

- Factory Tasarım Deseni

Factory tasarım deseni, creational (oluşturulma) tasarım desenlerinden biridir ve nesne oluşturma süreçlerini soyutlamak ve alt sınıfların nesne oluşturmasını sağlamak amacıyla kullanılır. Bu desen, bir sınıfın doğrudan nesne oluşturmasını engeller ve nesne oluşturma süreçlerini bir "fabrika" sınıfına (Factory Class) devreder. Bu sayede, uygulamanın genelinden nesne oluşturma süreçleri merkezi bir şekilde kontrol edilebilir ve nesnelerin nasıl oluşturulacağı daha esnek bir şekilde değiştirilebilir.

Tabii ki! Factory tasarım deseni, creational (oluşturulma) tasarım desenlerinden biridir ve nesne oluşturma süreçlerini soyutlamak ve alt sınıfların nesne oluşturmasını sağlamak amacıyla kullanılır. Bu desen, bir sınıfın doğrudan nesne oluşturmasını engeller ve nesne oluşturma süreçlerini bir "fabrika" sınıfına (Factory Class) devreder. Bu sayede, uygulamanın genelinden nesne oluşturma süreçleri merkezi bir şekilde kontrol edilebilir ve nesnelerin nasıl oluşturulacağı daha esnek bir şekilde değiştirilebilir.

C# ile bir Factory tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Abstract Product (Soyut Ürün) sınıfı: Nesnelerin arayüzünü tanımlar. Bu sınıf, oluşturulacak nesnelerin tüm alt sınıflarının uyması gereken bir sözleşme sağlar.

  2. Concrete Product (Somut Ürün) sınıfları: Abstract Product sınıfını uygulayan somut sınıflardır. Yani, gerçek nesne örneklerini temsil ederler.

  3. Abstract Factory (Soyut Fabrika) sınıfı: Nesne oluşturma metotlarının tanımlandığı soyut bir sınıftır. Bu sınıf, somut fabrika sınıflarının uyması gereken bir sözleşme sağlar.

  4. Concrete Factory (Somut Fabrika) sınıfları: Abstract Factory sınıfını uygulayan somut sınıflardır. Yani, belirli somut ürünleri oluşturan sınıflardır.

  5. Client (İstemci) sınıfı: Factory desenini kullanacak olan sınıftır. Bu sınıf, nesne oluşturma işlemlerini somut fabrika sınıflarına bırakır ve nesneleri kullanır.

İşte C# örneği ile bir Factory tasarım deseni:

// Adım 1: Abstract Product (Soyut Ürün) sınıfı
public abstract class Vehicle
{
    public abstract void Drive();
}

// Adım 2: Concrete Product (Somut Ürün) sınıfları
public class Car : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Car is being driven.");
    }
}

public class Motorcycle : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Motorcycle is being driven.");
    }
}

// Adım 3: Abstract Factory (Soyut Fabrika) sınıfı
public abstract class VehicleFactory
{
    public abstract Vehicle CreateVehicle();
}

// Adım 4: Concrete Factory (Somut Fabrika) sınıfları
public class CarFactory : VehicleFactory
{
    public override Vehicle CreateVehicle()
    {
        return new Car();
    }
}

public class MotorcycleFactory : VehicleFactory
{
    public override Vehicle CreateVehicle()
    {
        return new Motorcycle();
    }
}

// Adım 5: Client (İstemci) sınıfı
public class Client
{
    private Vehicle vehicle;

    public Client(VehicleFactory factory)
    {
        // Factory sınıfından oluşturulan nesneyi alıyoruz.
        vehicle = factory.CreateVehicle();
    }

    public void DriveVehicle()
    {
        vehicle.Drive();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // İstemci, CarFactory'den bir arabayı kullanmak istiyor.
        VehicleFactory carFactory = new CarFactory();
        Client carClient = new Client(carFactory);
        carClient.DriveVehicle(); // "Car is being driven." mesajı yazdırılır.

        // İstemci, MotorcycleFactory'den bir motosikleti kullanmak istiyor.
        VehicleFactory motorcycleFactory = new MotorcycleFactory();
        Client motorcycleClient = new Client(motorcycleFactory);
        motorcycleClient.DriveVehicle(); // "Motorcycle is being driven." mesajı yazdırılır.
    }
}

Yukarıdaki kod, Factory tasarım desenini basit bir şekilde kullanıyor. Abstract Product sınıfı olan Vehicle, somut ürünler olan Car ve Motorcycle sınıflarını uyguluyor. Abstract Factory sınıfı olan VehicleFactory, somut fabrika sınıfları CarFactory ve MotorcycleFactory tarafından uygulanıyor. İstemci, hangi tür aracı kullanmak istediğini belirtmek için VehicleFactory sınıfından türetilen bir fabrika nesnesini alıyor. Bu sayede, nesne oluşturma süreci istemciden soyutlanmış oluyor ve farklı somut fabrika sınıfları kullanılarak farklı türde araçlar oluşturulabiliyor.

- Abstract Factory Tasarım Deseni

Abstract Factory tasarım deseni, creational (oluşturulma) tasarım desenlerinden biridir ve birbirleriyle bağlantılı ve birbiriyle uyumlu nesnelerin ailesini oluşturmak için kullanılır. Bu desen, birbiriyle ilişkili birden fazla nesneyi oluşturmak için soyutlama sağlar ve somut nesnelerin oluşturulmasını alt sınıflara devreder. Bu sayede, birbiriyle uyumlu nesneleri bir araya getiren bir aile oluşturabiliriz ve bu aileyi kolayca değiştirebiliriz.

Abstract Factory tasarım deseni, creational (oluşturulma) tasarım desenlerinden biridir ve birbirleriyle bağlantılı ve birbiriyle uyumlu nesnelerin ailesini oluşturmak için kullanılır. Bu desen, birbiriyle ilişkili birden fazla nesneyi oluşturmak için soyutlama sağlar ve somut nesnelerin oluşturulmasını alt sınıflara devreder. Bu sayede, birbiriyle uyumlu nesneleri bir araya getiren bir aile oluşturabiliriz ve bu aileyi kolayca değiştirebiliriz.

C# ile bir Abstract Factory tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Abstract Product A ve Abstract Product B (Soyut Ürün A ve Soyut Ürün B) sınıfları: İlgili somut ürün ailesinin üyelerini tanımlar. Bu sınıflar, oluşturulacak somut ürünlerin tüm alt sınıflarının uyması gereken bir sözleşme sağlar.

  2. Concrete Product A1, Concrete Product A2, Concrete Product B1 ve Concrete Product B2 (Somut Ürün A1, Somut Ürün A2, Somut Ürün B1 ve Somut Ürün B2) sınıfları: Abstract Product A ve Abstract Product B sınıflarını uygulayan somut sınıflardır. Yani, gerçek nesne örneklerini temsil ederler.

  3. Abstract Factory (Soyut Fabrika) sınıfı: Abstract Product A ve Abstract Product B için nesne oluşturma metotlarının tanımlandığı soyut bir sınıftır. Bu sınıf, somut fabrika sınıflarının uyması gereken bir sözleşme sağlar.

  4. Concrete Factory 1 ve Concrete Factory 2 (Somut Fabrika 1 ve Somut Fabrika 2) sınıfları: Abstract Factory sınıfını uygulayan somut sınıflardır. Yani, belirli somut ürün ailesi için ürünleri oluşturan sınıflardır.

  5. Client (İstemci) sınıfı: Abstract Factory desenini kullanacak olan sınıftır. Bu sınıf, nesne oluşturma işlemlerini somut fabrika sınıflarına bırakır ve nesneleri kullanır.

İşte C# örneği ile bir Abstract Factory tasarım deseni:

// Adım 1: Abstract Product A
public interface IChair
{
    void SitOn();
}

// Adım 2: Concrete Product A1
public class ModernChair : IChair
{
    public void SitOn()
    {
        Console.WriteLine("Sitting on a modern chair.");
    }
}

// Adım 2: Concrete Product A2
public class VictorianChair : IChair
{
    public void SitOn()
    {
        Console.WriteLine("Sitting on a Victorian chair.");
    }
}

// Adım 1: Abstract Product B
public interface ITable
{
    void PutOn();
}

// Adım 2: Concrete Product B1
public class ModernTable : ITable
{
    public void PutOn()
    {
        Console.WriteLine("Putting something on a modern table.");
    }
}

// Adım 2: Concrete Product B2
public class VictorianTable : ITable
{
    public void PutOn()
    {
        Console.WriteLine("Putting something on a Victorian table.");
    }
}

// Adım 3: Abstract Factory
public interface IFurnitureFactory
{
    IChair CreateChair();
    ITable CreateTable();
}

// Adım 4: Concrete Factory 1
public class ModernFurnitureFactory : IFurnitureFactory
{
    public IChair CreateChair()
    {
        return new ModernChair();
    }

    public ITable CreateTable()
    {
        return new ModernTable();
    }
}

// Adım 4: Concrete Factory 2
public class VictorianFurnitureFactory : IFurnitureFactory
{
    public IChair CreateChair()
    {
        return new VictorianChair();
    }

    public ITable CreateTable()
    {
        return new VictorianTable();
    }
}

// Adım 5: Client (İstemci) sınıfı
public class Client
{
    private IChair chair;
    private ITable table;

    public Client(IFurnitureFactory factory)
    {
        // Factory sınıfından oluşturulan nesneleri alıyoruz.
        chair = factory.CreateChair();
        table = factory.CreateTable();
    }

    public void UseFurniture()
    {
        chair.SitOn();
        table.PutOn();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // İstemci, ModernFurnitureFactory'den mobilya kullanmak istiyor.
        IFurnitureFactory modernFactory = new ModernFurnitureFactory();
        Client modernClient = new Client(modernFactory);
        modernClient.UseFurniture(); // "Sitting on a modern chair." ve "Putting something on a modern table." mesajları yazdırılır.

        // İstemci, VictorianFurnitureFactory'den mobilya kullanmak istiyor.
        IFurnitureFactory victorianFactory = new VictorianFurnitureFactory();
        Client victorianClient = new Client(victorianFactory);
        victorianClient.UseFurniture(); // "Sitting on a Victorian chair." ve "Putting something on a Victorian table." mesajları yazdırılır.
    }
}

Yukarıdaki kodda, Abstract Factory tasarım deseni kullanılarak mobilya üretimi simüle ediliyor. IChair ve ITable gibi Abstract Product sınıfları, ilgili somut ürün ailesinin üyelerini temsil eder. ModernChair, VictorianChair, ModernTable ve VictorianTable gibi Concrete Product sınıfları, Abstract Product sınıflarını uygular. IFurnitureFactory ise Abstract Factory sınıfını tanımlar ve somut fabrika sınıflar ModernFurnitureFactory ve VictorianFurnitureFactory bu sınıftan türetilir. İstemci, hangi tarzda mobilya kullanmak istediğini belirtmek için IFurnitureFactory sınıfından türetilen bir fabrika nesnesini alır ve mobilyaları kullanır. Bu sayede, nesne oluşturma süreci istemciden soyutlanmış olur ve farklı stilde mobilyaları farklı fabrika sınıfları ile oluşturabiliriz.

- Builder Tasarım Deseni

Builder tasarım deseni, creational (oluşturulma) tasarım desenlerinden biridir ve karmaşık nesnelerin adım adım oluşturulmasını sağlar. Bu desen, bir nesnenin farklı parçalarını birleştirerek nesnenin farklı varyasyonlarını oluşturmak için kullanılır. Böylece, bir nesnenin oluşturulma sürecini soyutlayarak, nesne yapısını karmaşıklaştırmadan nesne varyasyonlarının oluşturulmasını kolaylaştırır.

C# ile bir Builder tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Product (Ürün) sınıfı: Oluşturulacak nesneyi temsil eder. Bu sınıf, oluşturulacak nesnenin farklı özelliklerini ve parçalarını içerir.

  2. Builder (Oluşturucu) sınıfı: Abstract Product sınıfını uygulayan ve nesne oluşturulma adımlarını tanımlayan soyut bir sınıftır. Bu sınıf, somut builder sınıflarının uyması gereken bir sözleşme sağlar.

  3. Concrete Builder (Somut Oluşturucu) sınıfı: Builder sınıfını uygulayan somut bir sınıftır. Bu sınıf, Product sınıfının belirli özelliklerini ve parçalarını oluşturan ve nesneyi oluşturmak için adım adım yönergeler sağlayan sınıftır.

  4. Director (Yönetici) sınıfı: Builder sınıfını kullanarak nesne oluşturma sürecini yönetir. Bu sınıf, nesnenin nasıl oluşturulacağını belirler ve Concrete Builder sınıfını kullanarak nesneyi oluşturur.

İşte C# örneği ile bir Builder tasarım deseni:

// Adım 1: Product (Ürün) sınıfı
public class Pizza
{
    public string Dough { get; set; }
    public string Sauce { get; set; }
    public string Topping { get; set; }

    public void Display()
    {
        Console.WriteLine($"Pizza with {Dough} dough, {Sauce} sauce, and {Topping} topping.");
    }
}

// Adım 2: Builder (Oluşturucu) sınıfı
public abstract class PizzaBuilder
{
    protected Pizza pizza;

    public void CreateNewPizza()
    {
        pizza = new Pizza();
    }

    public Pizza GetPizza()
    {
        return pizza;
    }

    public abstract void BuildDough();
    public abstract void BuildSauce();
    public abstract void BuildTopping();
}

// Adım 3: Concrete Builder (Somut Oluşturucu) sınıfı
public class MargheritaPizzaBuilder : PizzaBuilder
{
    public override void BuildDough()
    {
        pizza.Dough = "Thin crust";
    }

    public override void BuildSauce()
    {
        pizza.Sauce = "Tomato sauce";
    }

    public override void BuildTopping()
    {
        pizza.Topping = "Mozzarella cheese";
    }
}

public class PepperoniPizzaBuilder : PizzaBuilder
{
    public override void BuildDough()
    {
        pizza.Dough = "Thick crust";
    }

    public override void BuildSauce()
    {
        pizza.Sauce = "Tomato sauce";
    }

    public override void BuildTopping()
    {
        pizza.Topping = "Pepperoni and cheese";
    }
}

// Adım 4: Director (Yönetici) sınıfı
public class PizzaDirector
{
    private PizzaBuilder pizzaBuilder;

    public PizzaDirector(PizzaBuilder builder)
    {
        pizzaBuilder = builder;
    }

    public void MakePizza()
    {
        pizzaBuilder.CreateNewPizza();
        pizzaBuilder.BuildDough();
        pizzaBuilder.BuildSauce();
        pizzaBuilder.BuildTopping();
    }

    public Pizza GetPizza()
    {
        return pizzaBuilder.GetPizza();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Yönetici, MargheritaPizzaBuilder'ı kullanarak pizzayı oluşturuyor.
        PizzaBuilder builder1 = new MargheritaPizzaBuilder();
        PizzaDirector director1 = new PizzaDirector(builder1);
        director1.MakePizza();
        Pizza pizza1 = director1.GetPizza();
        pizza1.Display(); // "Pizza with Thin crust dough, Tomato sauce sauce, and Mozzarella cheese topping."

        // Yönetici, PepperoniPizzaBuilder'ı kullanarak pizzayı oluşturuyor.
        PizzaBuilder builder2 = new PepperoniPizzaBuilder();
        PizzaDirector director2 = new PizzaDirector(builder2);
        director2.MakePizza();
        Pizza pizza2 = director2.GetPizza();
        pizza2.Display(); // "Pizza with Thick crust dough, Tomato sauce sauce, and Pepperoni and cheese topping."
    }
}

Yukarıdaki kodda, Builder tasarım deseni kullanılarak pizzalar oluşturuluyor. Pizza sınıfı, oluşturulacak nesneyi temsil eder ve farklı özelliklerini içerir. PizzaBuilder soyut sınıfı, somut builder sınıflarının uyması gereken sözleşmeyi belirtir ve nesne oluşturulma adımlarını içerir. MargheritaPizzaBuilder ve PepperoniPizzaBuilder gibi Concrete Builder sınıfları, PizzaBuilder sınıfını uygular ve farklı pizzaların oluşturulma süreçlerini belirler. PizzaDirector sınıfı ise nesne oluşturma sürecini yönetir ve Concrete Builder sınıflarını kullanarak pizzaları oluşturur.

- Prototype Tasarım Deseni

Prototype tasarım deseni, creational (oluşturulma) tasarım desenlerinden biridir ve nesne klonlamak için kullanılır. Bu desen, mevcut bir nesnenin kopyasını oluşturarak yeni nesnelerin oluşturulmasını kolaylaştırır. Prototype deseni, nesne oluşturma maliyetini azaltır ve nesnelerin kopyalanmasıyla elde edilen yeni nesnelerin başlangıç durumları aynı olur.

C# ile bir Prototype tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Prototype (Prototip) sınıfı: Kopyalanacak nesnelerin arayüzünü tanımlar. Bu sınıf, klonlama işlemini gerçekleştirecek soyut bir klonlama metodu içerir.

  2. ConcretePrototype (Somut Prototip) sınıfları: Prototype sınıfını uygulayan somut sınıflardır. Yani, gerçek nesne örneklerini temsil ederler.

  3. Client (İstemci) sınıfı: Prototype desenini kullanacak olan sınıftır. Bu sınıf, nesne klonlama işlemini başlatır ve yeni nesneleri kullanır.

İşte C# örneği ile bir Prototype tasarım deseni:

using System;

// Adım 1: Prototype (Prototip) sınıfı
public abstract class Shape : ICloneable
{
    protected string type;

    public abstract void Draw();

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

// Adım 2: ConcretePrototype (Somut Prototip) sınıfları
public class Circle : Shape
{
    public Circle()
    {
        type = "Circle";
    }

    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}

public class Square : Shape
{
    public Square()
    {
        type = "Square";
    }

    public override void Draw()
    {
        Console.WriteLine("Drawing a square.");
    }
}

// Adım 3: Client (İstemci) sınıfı
public class Client
{
    private Shape shape;

    public Client(Shape shape)
    {
        this.shape = shape;
    }

    public Shape CloneShape()
    {
        return (Shape)shape.Clone();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // İstemci, Circle prototipini kullanarak yeni bir Circle nesnesi oluşturuyor.
        Shape circlePrototype = new Circle();
        Client client1 = new Client(circlePrototype);
        Shape clonedCircle = client1.CloneShape();
        clonedCircle.Draw(); // "Drawing a circle." mesajı yazdırılır.

        // İstemci, Square prototipini kullanarak yeni bir Square nesnesi oluşturuyor.
        Shape squarePrototype = new Square();
        Client client2 = new Client(squarePrototype);
        Shape clonedSquare = client2.CloneShape();
        clonedSquare.Draw(); // "Drawing a square." mesajı yazdırılır.
    }
}

Yukarıdaki kodda, Prototype tasarım deseni kullanılarak şekil nesneleri oluşturuluyor. Shape soyut sınıfı, nesne klonlama işlemini gerçekleştirecek soyut bir Clone metodu içerir. Circle ve Square gibi Concrete Prototype sınıfları, Shape sınıfını uygular ve gerçek nesne örneklerini temsil eder. Client sınıfı ise nesne klonlama işlemini başlatır ve Shape sınıfının Clone metoduyla yeni nesneleri oluşturur. Böylece, yeni nesnelerin başlangıç durumları, prototip nesneleriyle aynı olur ve nesne oluşturma maliyeti azaltılmış olur.

Structural (Yapısal) Tasarım Desenleri

- Adapter Tasarım Deseni

Adapter tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve farklı arabirimlere sahip olan sınıfların birlikte çalışabilmesini sağlar. Bu desen, mevcut bir sınıfın arabirimini başka bir arabirime dönüştürmek için kullanılır. Bu sayede, bir sınıfın içindeki yapıyı veya fonksiyonelliği değiştirmeden, farklı bir arabirimi kullanabiliriz.

Adapter tasarım deseninin iki ana türü vardır:

  1. Sınıf Adaptörü (Class Adapter): Bir sınıfı hedef arabirim üzerinden uygulayan bir adaptör sınıf kullanarak farklı bir arabirimi hedef sınıfın arabirimine dönüştürür.

  2. Nesne Adaptörü (Object Adapter): Hedef arabirimi uygulayan bir adaptör nesnesi kullanarak farklı bir arabirimi hedef sınıfa dönüştürür. Yani, adapte edilecek sınıfı, adaptör nesnesinin içine alarak uygun arayüzü sağlar.

C# ile bir Adapter tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Target (Hedef) arabirim: Adapter'ın hedeflediği ve uyumlu olmasını istediğimiz arabirim.

  2. Adaptee (Uyumlu Olmayan) sınıf: Mevcut olan ve uyumlu olmayan arabirime sahip olan sınıf.

  3. Adapter sınıfı: Target arabirimini uygulayan ve Adaptee sınıfını içeren adaptör sınıfı.

İşte C# örneği ile bir Adapter tasarım deseni:

// Adım 1: Target (Hedef) arabirim
public interface IShape
{
    void DisplayShape();
}

// Adım 2: Adaptee (Uyumlu Olmayan) sınıf
public class Rectangle
{
    public void DisplayRectangle()
    {
        Console.WriteLine("Rectangle is displayed.");
    }
}

// Adım 3: Adapter sınıfı
public class RectangleAdapter : IShape
{
    private Rectangle rectangle;

    public RectangleAdapter(Rectangle rectangle)
    {
        this.rectangle = rectangle;
    }

    public void DisplayShape()
    {
        rectangle.DisplayRectangle();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Uyumlu olmayan Rectangle sınıfını, IShape arabirimine dönüştüren bir adaptör kullanıyoruz.
        Rectangle rectangle = new Rectangle();
        IShape shapeAdapter = new RectangleAdapter(rectangle);
        shapeAdapter.DisplayShape(); // "Rectangle is displayed." mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Rectangle sınıfı olduğunu ve bunun uyumlu olmayan bir arabirime (IShape) sahip olduğunu varsayalım. Target arabirimini temsil eden IShape arabirimini tanımladık ve Adaptee olarak düşündüğümüz Rectangle sınıfını oluşturduk. RectangleAdapter sınıfı, IShape arabirimini uygulayarak uyumlu bir arabirim sağlıyor ve içinde bir Rectangle nesnesini kullanarak IShape.DisplayShape metodu ile Rectangle.DisplayRectangle metodunu eşleştiriyor. Bu sayede, Rectangle sınıfını IShape arabirimine uygun hale getiriyoruz ve mevcut uygulamada IShape arabirimini kullanan diğer sınıfların Rectangle sınıfı ile uyumlu çalışmasını sağlıyoruz.

- Bridge Tasarım Deseni

Bridge tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve soyutlama ve uygulama detaylarını birbirinden ayırmak için kullanılır. Bu desen, iki ayrı hiyerarşiyi birbirinden bağımsız olarak değiştirebilme esnekliği sağlar ve sınıflar arasındaki sert bağımlılığı önler.

Bridge tasarım deseni, "Abstraction" ve "Implementation" olarak adlandırılan iki ayrı hiyerarşiyi kullanır:

  • Abstraction: Bu hiyerarşi, soyutlamayı temsil eder ve uygulama detaylarından bağımsız bir arayüz sunar. Genellikle iş mantığını tanımlayan sınıflardan oluşur.

  • Implementation: Bu hiyerarşi, uygulama detaylarını temsil eder ve soyutlama tarafından sunulan arayüzü uygular. Genellikle uygulama detaylarını belirleyen sınıflardan oluşur.

Bridge tasarım deseni, bu iki hiyerarşiyi birbirinden ayrı tutarak, daha esnek ve kolay değiştirilebilir bir tasarım elde etmeyi sağlar.

C# ile bir Bridge tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Abstraction sınıfı: Uygulama detaylarından bağımsız bir arayüz sunar ve içinde bir Implementation referansı bulundurur.

  2. RefinedAbstraction sınıfı: Abstraction sınıfını genişletir ve uygulama detaylarını tanımlar.

  3. Implementation sınıfı: Abstraction tarafından sunulan arayüzü uygular.

  4. ConcreteImplementation sınıfı: Implementation sınıfını genişletir ve uygulama detaylarını belirler.

İşte C# örneği ile bir Bridge tasarım deseni:

// Adım 1: Abstraction sınıfı
public abstract class RemoteControl
{
    protected IDevice device;

    public RemoteControl(IDevice device)
    {
        this.device = device;
    }

    public abstract void TurnOn();
    public abstract void TurnOff();
    public abstract void SetChannel(int channel);
}

// Adım 2: RefinedAbstraction sınıfı
public class TVRemoteControl : RemoteControl
{
    public TVRemoteControl(IDevice device) : base(device)
    {
    }

    public override void TurnOn()
    {
        device.TurnOn();
    }

    public override void TurnOff()
    {
        device.TurnOff();
    }

    public override void SetChannel(int channel)
    {
        device.SetChannel(channel);
    }
}

// Adım 3: Implementation sınıfı
public interface IDevice
{
    void TurnOn();
    void TurnOff();
    void SetChannel(int channel);
}

// Adım 4: ConcreteImplementation sınıfı
public class TV : IDevice
{
    public void TurnOn()
    {
        Console.WriteLine("TV is turned on.");
    }

    public void TurnOff()
    {
        Console.WriteLine("TV is turned off.");
    }

    public void SetChannel(int channel)
    {
        Console.WriteLine("TV channel is set to " + channel);
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Abstraction sınıfını kullanarak TVRemoteControl oluşturuyoruz.
        IDevice tvDevice = new TV();
        RemoteControl remoteControl = new TVRemoteControl(tvDevice);

        // TV'yi açıyoruz.
        remoteControl.TurnOn(); // "TV is turned on." mesajı yazdırılır.

        // TV'yi kapatıyoruz.
        remoteControl.TurnOff(); // "TV is turned off." mesajı yazdırılır.

        // TV'nin kanalını değiştiriyoruz.
        remoteControl.SetChannel(5); // "TV channel is set to 5" mesajı yazdırılır.
    }
}

Yukarıdaki kodda, Bridge tasarım deseni kullanılarak TV ve uzaktan kumanda ilişkisi tasarlanmıştır. RemoteControl soyut sınıfı, IDevice arayüzüne sahip bir cihazı referans eder. TVRemoteControl sınıfı, RemoteControl sınıfını genişletir ve uygulama detaylarını belirler. IDevice arayüzü, TV'nin temel işlevlerini tanımlar. TV sınıfı, IDevice arayüzünü uygular ve TV'nin işlevlerini gerçekleştirir.

Bu şekilde, RemoteControl soyut sınıfı TV'nin detaylarından bağımsız olarak uzaktan kumanda işlevlerini tanımlarken, TV sınıfı TV'nin işlevlerini belirler. Bu sayede, yeni cihazlar eklemek veya uzaktan kumandayı değiştirmek istediğimizde RemoteControl veya IDevice hiyerarşilerini değiştirmemiz yeterli olacaktır. Bu, sınıflar arasındaki bağımlılığı azaltır ve sistemi esnek hale getirir.

- Composite Tasarım Deseni

Composite tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve nesnelerin ağaç yapısını temsil etmek için kullanılır. Bu desen, ağaç yapısındaki tüm düğümleri (leaf) ve alt ağaçları (composite) tek bir yapı altında birleştirmemize olanak tanır. Böylece, tüm nesneleri tek bir arabirim üzerinden yönetebiliriz.

Composite tasarım deseni, "Component", "Leaf" ve "Composite" olarak adlandırılan üç ana bileşeni içerir:

  • Component: Tüm düğümlerin uyması gereken ortak arayüzü tanımlar. Bu sınıf hem leaf hem de composite nesneler için ortak işlevleri içerir.

  • Leaf: Alt düğümleri olmayan yaprak düğümleri temsil eder. Yani, bu düğümler alt düğümlere sahip değillerdir.

  • Composite: Alt düğümleri olan düğümleri temsil eder. Yani, bu düğümler alt düğümlere sahip olabilir ve bu alt düğümler de leaf veya composite nesneleri olabilir.

C# ile bir Composite tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Component sınıfı: Leaf ve Composite nesnelerinin uyması gereken ortak arayüzü tanımlar.

  2. Leaf sınıfı: Alt düğümleri olmayan yaprak düğümleri temsil eder ve Component sınıfını uygular.

  3. Composite sınıfı: Alt düğümleri olan düğümleri temsil eder ve Component sınıfını uygular. Bu sınıf aynı zamanda alt düğümleri yönetir.

İşte C# örneği ile bir Composite tasarım deseni:

using System;
using System.Collections.Generic;

// Adım 1: Component sınıfı
public interface IGraphic
{
    void Draw();
}

// Adım 2: Leaf sınıfı
public class Ellipse : IGraphic
{
    public void Draw()
    {
        Console.WriteLine("Drawing an ellipse");
    }
}

// Adım 3: Composite sınıfı
public class CompositeGraphic : IGraphic
{
    private List<IGraphic> graphics = new List<IGraphic>();

    public void Add(IGraphic graphic)
    {
        graphics.Add(graphic);
    }

    public void Remove(IGraphic graphic)
    {
        graphics.Remove(graphic);
    }

    public void Draw()
    {
        Console.WriteLine("Drawing a composite graphic");
        foreach (IGraphic graphic in graphics)
        {
            graphic.Draw();
        }
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Yaprak düğümler (Leaf) oluşturuyoruz.
        IGraphic ellipse1 = new Ellipse();
        IGraphic ellipse2 = new Ellipse();

        // Bir bileşik grafik (Composite) oluşturuyoruz ve yaprak düğümleri ekliyoruz.
        CompositeGraphic compositeGraphic1 = new CompositeGraphic();
        compositeGraphic1.Add(ellipse1);
        compositeGraphic1.Add(ellipse2);

        // Başka bir yaprak düğüm oluşturuyoruz.
        IGraphic ellipse3 = new Ellipse();

        // Yeni bir bileşik grafik oluşturuyoruz ve yaprak düğümü ekliyoruz.
        CompositeGraphic compositeGraphic2 = new CompositeGraphic();
        compositeGraphic2.Add(ellipse3);

        // Bir üst düzey bileşik grafik oluşturuyoruz ve önceki bileşik grafikleri ekliyoruz.
        CompositeGraphic allGraphics = new CompositeGraphic();
        allGraphics.Add(compositeGraphic1);
        allGraphics.Add(compositeGraphic2);

        // Tüm grafiği çiziyoruz. Çıktıda yaprak düğümler ve bileşik grafikler çizdirilecektir.
        allGraphics.Draw();
    }
}

Yukarıdaki kodda, bir grafik yapısını temsil etmek için Composite tasarım deseni kullanılmıştır. IGraphic arayüzü, hem yaprak düğümleri (Ellipse) hem de bileşik grafikleri (CompositeGraphic) temsil eden sınıfların uyması gereken bir arayüzü tanımlar. Ellipse sınıfı, yaprak düğümü temsil eder ve IGraphic arayüzünü uygular. CompositeGraphic sınıfı ise bileşik grafikleri temsil eder ve IGraphic arayüzünü uygular. Bu sınıf, içinde bulundurduğu List<IGraphic> koleksiyonu ile alt düğümleri yönetir. Böylece, tüm grafiği oluşturan yaprak düğümleri ve bileşik grafikleri tek bir yapı altında birleştiririz. Bu sayede, tüm nesneleri IGraphic arayüzü üzerinden tek bir yöntemle (Draw) yönetebiliriz.

- Decorator Tasarım Deseni

Decorator tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve nesnelerin davranışlarını dinamik olarak değiştirmek veya eklemek için kullanılır. Bu desen, nesneleri sarmalayan veya süsleyen (decorate) farklı dekoratör sınıfların kullanılmasıyla davranışlarını genişletir.

Decorator tasarım deseni, aynı arabirim veya soyut sınıftan türetilen farklı dekoratör sınıflarının bir araya gelmesiyle çalışır. Her dekoratör sınıfı, bir bileşen nesnesini sarmalar ve ek işlevselliği veya davranışları ekler. Bu sayede, temel nesne üzerinde yapılan değişiklikler, tüm dekoratörlerin etkilenmesini sağlar.

C# ile bir Decorator tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Component (Bileşen) sınıfı: Temel nesnenin (bileşenin) arayüzünü tanımlar. Bu sınıf, dekoratörlerin sarmalayacağı temel sınıftır.

  2. ConcreteComponent (Somut Bileşen) sınıfı: Component sınıfını uygular ve temel nesnenin (bileşenin) özelliklerini ve davranışlarını içerir.

  3. Decorator sınıfı: Component sınıfını uygular ve içinde bir Component referansı bulundurur. Bu sınıf, dekoratörlerin temel bileşeni sarmalayacağı soyut bir sınıftır.

  4. ConcreteDecorator (Somut Dekoratör) sınıfları: Decorator sınıfını uygular ve ek işlevselliği veya davranışları ekleyerek temel bileşeni sarmalar.

İşte C# örneği ile bir Decorator tasarım deseni:

using System;

// Adım 1: Component (Bileşen) sınıfı
public interface ICar
{
    void Assemble();
}

// Adım 2: ConcreteComponent (Somut Bileşen) sınıfı
public class BasicCar : ICar
{
    public void Assemble()
    {
        Console.WriteLine("Basic car is assembled.");
    }
}

// Adım 3: Decorator sınıfı
public abstract class CarDecorator : ICar
{
    protected ICar car;

    public CarDecorator(ICar car)
    {
        this.car = car;
    }

    public virtual void Assemble()
    {
        car.Assemble();
    }
}

// Adım 4: ConcreteDecorator (Somut Dekoratör) sınıfları
public class SportsCar : CarDecorator
{
    public SportsCar(ICar car) : base(car)
    {
    }

    public override void Assemble()
    {
        base.Assemble();
        Console.WriteLine("Sports car features are added.");
    }
}

public class LuxuryCar : CarDecorator
{
    public LuxuryCar(ICar car) : base(car)
    {
    }

    public override void Assemble()
    {
        base.Assemble();
        Console.WriteLine("Luxury car features are added.");
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Temel arabayı oluşturuyoruz.
        ICar basicCar = new BasicCar();

        // Spor arabayı saran bir dekoratör ekliyoruz.
        ICar sportsCar = new SportsCar(basicCar);
        sportsCar.Assemble();
        // Çıktı:
        // Basic car is assembled.
        // Sports car features are added.

        // Lüks arabayı saran bir dekoratör ekliyoruz.
        ICar luxuryCar = new LuxuryCar(basicCar);
        luxuryCar.Assemble();
        // Çıktı:
        // Basic car is assembled.
        // Luxury car features are added.
    }
}

Yukarıdaki kodda, bir arabayı temsil etmek için Decorator tasarım deseni kullanılmıştır. ICar arayüzü, arabaların temel davranışını tanımlar ve BasicCar sınıfı bu arayüzü uygular. CarDecorator soyut sınıfı, ICar arayüzünü uygular ve içinde bir ICar referansı bulundurur. SportsCar ve LuxuryCar gibi CarDecorator sınıfları, ICar arayüzünü uygular ve temel arabayı sarmalayarak ek işlevselliği ekler.

Böylece, BasicCar sınıfı temel arabayı temsil ederken, SportsCar ve LuxuryCar sınıfları bu arabayı saran dekoratörlerdir. Bu sayede, temel arabayı değiştirmeden farklı dekoratörleri ekleyerek spor veya lüks arabaları oluşturabiliriz. Bu desen, nesnelerin davranışlarını dinamik olarak değiştirme ve yeni işlevselliği eklemek için kullanışlı bir yöntem sağlar.

- Facade Tasarım Deseni

Facade tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve karmaşık bir alt sistemi basit ve tek bir arabirim aracılığıyla kullanılabilir hale getirmek için kullanılır. Bu desen, istemcinin karmaşık bir alt sistemi kullanmasını engelleyerek daha kolay bir arayüz sunar.

Facade deseni, istemcinin alt sistemle doğrudan etkileşim kurmasını önlemek için araya bir arayüz (facade) ekler. Bu sayede, alt sistemin değişmesi veya güncellenmesi durumunda sadece facade sınıfını güncellemek yeterli olur ve istemci kodunun değişmesine gerek kalmaz.

C# ile bir Facade tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Facade sınıfı: İstemciyle alt sistem arasında bir arabirim sağlar ve alt sistemdeki işlemleri yönetir.

  2. Alt sistem sınıfları: Karmaşık bir alt sistemi temsil eder. İstemci, alt sistemi doğrudan kullanmak yerine Facade üzerinden etkileşim kurar.

İşte C# örneği ile bir Facade tasarım deseni:

using System;

// Alt sistem sınıfları
public class SubSystemA
{
    public void OperationA()
    {
        Console.WriteLine("SubSystemA OperationA is called.");
    }
}

public class SubSystemB
{
    public void OperationB()
    {
        Console.WriteLine("SubSystemB OperationB is called.");
    }
}

public class SubSystemC
{
    public void OperationC()
    {
        Console.WriteLine("SubSystemC OperationC is called.");
    }
}

// Facade sınıfı
public class Facade
{
    private SubSystemA systemA;
    private SubSystemB systemB;
    private SubSystemC systemC;

    public Facade()
    {
        systemA = new SubSystemA();
        systemB = new SubSystemB();
        systemC = new SubSystemC();
    }

    public void Operation1()
    {
        Console.WriteLine("Facade Operation1 is called.");
        systemA.OperationA();
        systemB.OperationB();
    }

    public void Operation2()
    {
        Console.WriteLine("Facade Operation2 is called.");
        systemB.OperationB();
        systemC.OperationC();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Facade sınıfı üzerinden alt sistemle etkileşim kuruyoruz.
        Facade facade = new Facade();
        facade.Operation1();
        facade.Operation2();
    }
}

Yukarıdaki kodda, bir Facade tasarım deseni kullanılarak karmaşık bir alt sistemin basit bir arabirimle kullanımı sağlanmıştır. SubSystemA, SubSystemB ve SubSystemC sınıfları karmaşık alt sistemimizi temsil eder. Facade sınıfı, bu alt sistemle etkileşim kuracak bir arayüz sağlar ve alt sistemdeki işlemleri yönetir.

Facade sınıfının Operation1 ve Operation2 metotları, alt sistemdeki belirli işlemleri birleştirerek daha kolay bir kullanım sağlar. İstemci, karmaşık alt sistemi doğrudan kullanmak yerine Facade üzerinden işlemleri çağırır. Böylece, alt sistemdeki değişiklikler sadece Facade sınıfını etkiler ve istemci kodu değişmez. Facade tasarım deseni, büyük ve karmaşık sistemleri daha kolay yönetilebilir ve kullanılabilir hale getirir.

- Flyweight Tasarım Deseni

Flyweight tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve nesne oluşturma maliyetini azaltmak için kullanılır. Bu desen, benzer veya paylaşılan durumları olan nesneleri etkin bir şekilde paylaşarak bellek kullanımını optimize eder.

Flyweight tasarım deseni, iki temel yapıya sahiptir:

  1. Flyweight (Uçucu Nesne) sınıfı: Paylaşılan durumları içeren nesneleri temsil eder. Bu sınıf, mümkün olan en az bellek kullanımıyla nesneleri oluşturmalıdır. Paylaşılan durumlar, flyweight nesneler arasında aynı olacaktır.

  2. Context (Bağlam) sınıfı: Paylaşılan nesnelerin durumunu tutan ve bağlam bilgisini içeren dış durumları temsil eder. Bu sınıf, paylaşılan flyweight nesnelerini kullanarak çalışır.

C# ile bir Flyweight tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Flyweight (Uçucu Nesne) sınıfı: Paylaşılan durumları içeren nesneleri temsil eder.

  2. ConcreteFlyweight (Somut Uçucu Nesne) sınıfları: Flyweight sınıfını uygular ve durumları tutar.

  3. FlyweightFactory sınıfı: Flyweight nesnelerini yönetir ve paylaşılan nesneleri oluşturur.

İşte C# örneği ile bir Flyweight tasarım deseni:

using System;
using System.Collections.Generic;

// Adım 1: Flyweight (Uçucu Nesne) sınıfı
public interface ICarFlyweight
{
    void ShowCarDetails(string color);
}

// Adım 2: ConcreteFlyweight (Somut Uçucu Nesne) sınıfları
public class Car : ICarFlyweight
{
    private string make;
    private string model;

    public Car(string make, string model)
    {
        this.make = make;
        this.model = model;
    }

    public void ShowCarDetails(string color)
    {
        Console.WriteLine($"Car: {make}, Model: {model}, Color: {color}");
    }
}

// Adım 3: FlyweightFactory sınıfı
public class CarFactory
{
    private Dictionary<string, ICarFlyweight> cars = new Dictionary<string, ICarFlyweight>();

    public ICarFlyweight GetCar(string key)
    {
        if (cars.ContainsKey(key))
        {
            return cars[key];
        }
        else
        {
            ICarFlyweight car = new Car("SomeMake", "SomeModel");
            cars.Add(key, car);
            return car;
        }
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // FlyweightFactory üzerinden paylaşılan nesneleri oluşturuyoruz.
        CarFactory carFactory = new CarFactory();
        ICarFlyweight car1 = carFactory.GetCar("Car1");
        ICarFlyweight car2 = carFactory.GetCar("Car2");

        // Farklı bağlam bilgisi ile paylaşılan nesneleri kullanıyoruz.
        car1.ShowCarDetails("Red"); // "Car: SomeMake, Model: SomeModel, Color: Red"
        car2.ShowCarDetails("Blue"); // "Car: SomeMake, Model: SomeModel, Color: Blue"
    }
}

Yukarıdaki kodda, bir Flyweight tasarım deseni kullanılarak arabaların paylaşılan özelliklerini ve özdeş olmayan durumlarını yönetiyoruz. ICarFlyweight arayüzü, arabaların paylaşılan durumlarını temsil eder. Car sınıfı, paylaşılan özellikleri içeren ve ICarFlyweight arayüzünü uygulayan somut flyweight sınıfını temsil eder. CarFactory sınıfı, flyweight nesnelerini yönetir ve paylaşılan nesneleri oluşturur.

Kullanım örneğinde, farklı bağlam bilgisi ile ("Red" ve "Blue") paylaşılan flyweight nesnelerini kullanıyoruz. Her bağlamda, aynı flyweight nesnesi kullanılır ve paylaşılan durumlar ("SomeMake" ve "SomeModel") aynı kalır. Bu sayede, bellek kullanımı optimize edilir ve benzer nesnelerin tekrar tekrar oluşturulması önlenir.

- Proxy Tasarım Deseni

Proxy tasarım deseni, structural (yapısal) tasarım desenlerinden biridir ve başka bir nesnenin yerine geçerek veya onunla etkileşim kurarak o nesnenin davranışlarını kontrol etmek veya eklemek için kullanılır. Bu desen, gerçek nesne üzerinde bazı ek kontroller yapmak, gecikmeyi önlemek, erişimi kısıtlamak veya başka nedenlerle bir vekil (proxy) nesnesi kullanır.

Proxy tasarım deseni, iki temel yapıya sahiptir:

  1. Subject (Konu) arayüzü: Gerçek nesne ve proxy nesnenin uyguladığı arayüzdür. Bu arayüz, gerçek nesneyle proxy nesnesi arasında birliği sağlar.

  2. RealSubject (Gerçek Konu) sınıfı: Gerçek işi yapan gerçek nesneyi temsil eder.

  3. Proxy sınıfı: RealSubject sınıfını saran ve gerçek nesnenin işlevlerine aracılık eden sınıftır. Bu sınıf, gerçek nesneye erişimi kontrol edebilir veya bazı ek kontroller yapabilir.

C# ile bir Proxy tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Subject (Konu) arayüzü: Gerçek nesne ve proxy nesnenin uyguladığı arayüzü tanımlar.

  2. RealSubject (Gerçek Konu) sınıfı: Gerçek işi yapan gerçek nesneyi temsil eder ve Subject arayüzünü uygular.

  3. Proxy sınıfı: RealSubject sınıfını saran ve gerçek nesnenin işlevlerine aracılık eden sınıfıdır ve Subject arayüzünü uygular.

İşte C# örneği ile bir Proxy tasarım deseni:

using System;

// Adım 1: Subject (Konu) arayüzü
public interface IImage
{
    void DisplayImage();
}

// Adım 2: RealSubject (Gerçek Konu) sınıfı
public class RealImage : IImage
{
    private string fileName;

    public RealImage(string fileName)
    {
        this.fileName = fileName;
        LoadImageFromDisk();
    }

    public void DisplayImage()
    {
        Console.WriteLine("Displaying " + fileName);
    }

    private void LoadImageFromDisk()
    {
        Console.WriteLine("Loading " + fileName + " from disk");
    }
}

// Adım 3: Proxy sınıfı
public class ProxyImage : IImage
{
    private RealImage realImage;
    private string fileName;

    public ProxyImage(string fileName)
    {
        this.fileName = fileName;
    }

    public void DisplayImage()
    {
        if (realImage == null)
        {
            realImage = new RealImage(fileName);
        }
        realImage.DisplayImage();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // ProxyImage üzerinden gerçek resme erişiyoruz.
        IImage image = new ProxyImage("test.jpg");

        // Resmi yüklemediğimiz için bu aşamada gerçek resmi yüklemek için RealImage oluşturulur.
        image.DisplayImage(); // "Loading test.jpg from disk" ve "Displaying test.jpg" mesajları yazdırılır.

        // Resmi yüklediğimiz için bu aşamada RealImage tekrar oluşturulmaz.
        image.DisplayImage(); // "Displaying test.jpg" mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Proxy tasarım deseni kullanılarak bir resmi yüklemeyi geciktiren ve resme erişimi kontrol eden bir senaryo oluşturduk. IImage arayüzü, resimleri temsil eden bir konu arayüzüdür ve hem RealImage hem de ProxyImage sınıfları bu arayüzü uygular.

RealImage sınıfı, gerçek resmi yükleyen ve gösteren gerçek nesneyi temsil eder. ProxyImage sınıfı ise gerçek resmi geciktirerek resmi yükleme işlemini gerçekleştiren ve gerçek resme erişimi kontrol eden proxy nesnesini temsil eder.

Kullanım örneğinde, bir resmi yüklemeden önce ProxyImage üzerinden resme erişmeye çalışıyoruz. İlk erişimde gerçek resim yüklenir (RealImage oluşturulur) ve resim gösterilir. Sonraki erişimlerde resim yüklenmeden hemen gösterilir, çünkü ProxyImage artık gerçek resmi oluşturmaya ihtiyaç duymaz. Bu sayede, resmi tekrar tekrar yüklemeyerek ve gerçek resme gereksiz erişimlerden kaçınarak performansı artırabiliriz.

Behavioral (Davranışsal) Tasarım Desenleri

- Chain of Responsibility Tasarım Deseni

Chain of Responsibility tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve istemci isteğini işleyebilecek birden fazla nesne arasında bir zincir oluşturarak isteği işlemek için bu nesneler arasında sorumluluğu aktarma esasına dayanır. Bu desen, istemci isteği için doğru işleyiciyi bulana kadar zinciri takip eder.

Chain of Responsibility tasarım deseni, istemciden gelen bir isteği işleyebilecek farklı sınıfların olduğu bir hiyerarşi ile çalışır. İstemci, isteği ilk sınıfa iletir ve bu sınıf isteği işleyebilirse işlemi sonlandırır. İşlemi tamamlayamazsa isteği zincirin bir sonraki halkasına iletir. Bu şekilde zincir boyunca ilerler ve istek işlenene veya zincirin sonuna gelene kadar bu işlem tekrarlanır.

C# ile bir Chain of Responsibility tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Handler (İşleyici) sınıfı: Zincirdeki tüm işleyicilerin uyması gereken ortak arayüzü tanımlar.

  2. ConcreteHandler (Somut İşleyici) sınıfları: Handler sınıfını uygular ve belirli tipteki istekleri işler. İsteği işleyebiliyorsa işlemi sonlandırır; aksi takdirde isteği bir sonraki işleyiciye iletir.

İşte C# örneği ile bir Chain of Responsibility tasarım deseni:

using System;

// Adım 1: Handler (İşleyici) sınıfı
public abstract class Approver
{
    protected Approver successor; // Bir sonraki işleyiciyi temsil eder.

    public void SetSuccessor(Approver successor)
    {
        this.successor = successor;
    }

    public abstract void ProcessRequest(Purchase purchase);
}

// Adım 2: ConcreteHandler (Somut İşleyici) sınıfları
public class Manager : Approver
{
    public override void ProcessRequest(Purchase purchase)
    {
        if (purchase.Amount <= 1000)
        {
            Console.WriteLine($"{this.GetType().Name} approved the purchase request for {purchase.Product}.");
        }
        else if (successor != null)
        {
            successor.ProcessRequest(purchase);
        }
        else
        {
            Console.WriteLine($"The purchase request for {purchase.Product} cannot be approved.");
        }
    }
}

public class Director : Approver
{
    public override void ProcessRequest(Purchase purchase)
    {
        if (purchase.Amount <= 5000)
        {
            Console.WriteLine($"{this.GetType().Name} approved the purchase request for {purchase.Product}.");
        }
        else if (successor != null)
        {
            successor.ProcessRequest(purchase);
        }
        else
        {
            Console.WriteLine($"The purchase request for {purchase.Product} cannot be approved.");
        }
    }
}

public class President : Approver
{
    public override void ProcessRequest(Purchase purchase)
    {
        if (purchase.Amount <= 10000)
        {
            Console.WriteLine($"{this.GetType().Name} approved the purchase request for {purchase.Product}.");
        }
        else
        {
            Console.WriteLine($"The purchase request for {purchase.Product} cannot be approved.");
        }
    }
}

// İstek sınıfı
public class Purchase
{
    public string Product { get; set; }
    public double Amount { get; set; }

    public Purchase(string product, double amount)
    {
        Product = product;
        Amount = amount;
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Zincirdeki işleyicileri oluşturuyoruz.
        Approver manager = new Manager();
        Approver director = new Director();
        Approver president = new President();

        // Zinciri bağlıyoruz.
        manager.SetSuccessor(director);
        director.SetSuccessor(president);

        // İstemci isteği oluşturuyoruz ve zincirdeki ilk işleyiciye gönderiyoruz.
        Purchase purchase1 = new Purchase("Laptop", 800);
        manager.ProcessRequest(purchase1);

        Purchase purchase2 = new Purchase("Smartphone", 4000);
        manager.ProcessRequest(purchase2);

        Purchase purchase3 = new Purchase("Conference Table", 12000);
        manager.ProcessRequest(purchase3);
    }
}

Yukarıdaki kodda, bir Chain of Responsibility tasarım deseni kullanılarak satın alma onay sürecini temsil ediyoruz. Approver soyut sınıfı, zincirdeki işleyicilerin uyması gereken temel arayüzü tanımlar. Manager, Director ve President gibi Approver sınıfları, satın alımı onaylama yetkisi olan işleyicileri temsil eder ve bu işleyiciler farklı limitlerdeki satın alımları onaylayabilir. Purchase sınıfı, satın alma isteğini temsil eder.

Kullanım örneğinde, bir satın alma isteği oluşturup zincirdeki ilk işleyici olan Managera gönderiyoruz. Eğer satın alma tutarı, Manager'ın yetki limitini aşıyorsa istek otomatik olarak zincirdeki diğer işleyicilere aktarılır ve işlem onaylanır. Zincirin sonunda bir işleyici onaylamıyorsa istek reddedilir ve uygun mesaj yazdırılır. Bu şekilde, bir zincirde farklı işleyicileri sırayla deneyerek işlemi gerçekleştirebilir ve isteği onaylama işlemi kolayca özelleştirilebilir.

- Command Tasarım Deseni

Command tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir işlemi, bir nesnenin içerdiği veriyle birlikte bir komut nesnesi olarak paketleyerek istemci tarafından tetiklenebilir hale getirir. Bu desen, bir istemcinin bir sınıfın yöntemlerini çağırmasını soyutlar ve yöntem çağrısını nesne şeklinde temsil eder.

Command tasarım deseni, istemci ve alıcı (receiver) arasındaki bağı gevşetir ve istemci, alıcının iç yapısını bilmek zorunda kalmadan bir isteği gerçekleştirebilir. Aynı zamanda geri alma (undo) işlemlerini desteklemek için de kullanılabilir.

C# ile bir Command tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Command arayüzü: Komutları temsil eden bir arayüzdür. İçerisinde Execute adında bir metot bulunur.

  2. ConcreteCommand sınıfı: Command arayüzünü uygular ve bir alıcı (receiver) nesnesi ve ilgili yöntemi içeren komutları temsil eder.

  3. Receiver sınıfı: Komutları gerçekleştiren ve uygulayan alıcıdır.

  4. Invoker sınıfı: Komutları gerçekleştiren nesneleri tutar ve komutları tetikler.

İşte C# örneği ile bir Command tasarım deseni:

using System;

// Adım 1: Command arayüzü
public interface ICommand
{
    void Execute();
}

// Adım 2: ConcreteCommand sınıfı
public class LightOnCommand : ICommand
{
    private readonly Light light;

    public LightOnCommand(Light light)
    {
        this.light = light;
    }

    public void Execute()
    {
        light.TurnOn();
    }
}

// Adım 3: Receiver sınıfı
public class Light
{
    public void TurnOn()
    {
        Console.WriteLine("Light is on.");
    }

    public void TurnOff()
    {
        Console.WriteLine("Light is off.");
    }
}

// Adım 4: Invoker sınıfı
public class RemoteControl
{
    private ICommand command;

    public void SetCommand(ICommand command)
    {
        this.command = command;
    }

    public void PressButton()
    {
        command.Execute();
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Receiver nesnesi oluşturuyoruz.
        Light light = new Light();

        // ConcreteCommand nesnesini Receiver ile ilişkilendiriyoruz.
        ICommand lightOnCommand = new LightOnCommand(light);

        // Invoker nesnesi oluşturuyoruz ve komutu set ediyoruz.
        RemoteControl remoteControl = new RemoteControl();
        remoteControl.SetCommand(lightOnCommand);

        // Komutu tetikliyoruz.
        remoteControl.PressButton(); // "Light is on." mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Command tasarım deseni kullanılarak bir lambanın açma işlemi ele alınmıştır. ICommand arayüzü, komutları temsil eder ve Execute metodu komutları uygular. LightOnCommand sınıfı, ICommand arayüzünü uygular ve Light alıcısını temsil ederek lambayı açma işlemini gerçekleştirir. Light sınıfı, gerçekleştirilecek işlemleri içeren alıcıdır.

RemoteControl sınıfı, bir komutu tutan ve komutu tetikleyen invoker olarak görev yapar. İstemci, invoker olan RemoteControl sınıfını kullanarak istediği komutu tetikleyebilir. Böylece, komutların istemci tarafından uygulanmasını soyutlayarak istemcinin alıcı hakkında bilgi sahibi olmasını önleriz. Bu şekilde, yeni komutlar eklemek veya komutları değiştirmek daha kolay hale gelir.

- Interpreter Tasarım Deseni

Interpreter tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir dilin belirli kurallarına göre ifadeleri yorumlamak için kullanılır. Bu desen, belirli bir dilde yazılmış ifadeleri bir dil yapısını temsil eden nesnelere çevirerek bu ifadelerin yorumlanmasını sağlar.

Interpreter tasarım deseni, yorumlanacak ifadeleri temsil eden TerminalExpression ve NonTerminalExpression olmak üzere iki temel sınıf yapısına sahiptir.

  • TerminalExpression: Bir dilin en küçük bileşenlerini temsil eder. Bu sınıf, yorumlanacak ifadenin yaprak düğümlerini temsil eder.

  • NonTerminalExpression: Birden fazla TerminalExpression veya başka NonTerminalExpression ile birleştirilerek daha büyük ifadeleri temsil eder. Bu sınıf, yorumlanacak ifadenin iç düğümlerini temsil eder.

C# ile bir Interpreter tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Expression arayüzü: Yorumlanacak ifadeleri temsil eden arayüzü tanımlar.

  2. TerminalExpression sınıfı: Bir dilin en küçük bileşenlerini temsil eder ve Expression arayüzünü uygular.

  3. NonTerminalExpression sınıfı: Birden fazla TerminalExpression veya başka NonTerminalExpression ile birleştirilerek daha büyük ifadeleri temsil eder ve Expression arayüzünü uygular.

  4. Context sınıfı: İfadeyi yorumlamak için gerekli bilgileri içeren nesneyi temsil eder.

İşte C# örneği ile bir Interpreter tasarım deseni:

 
using System;
using System.Collections.Generic;

// Adım 1: Expression arayüzü
public interface IExpression
{
    int Interpret(Context context);
}

// Adım 2: TerminalExpression sınıfı
public class NumberExpression : IExpression
{
    private int number;

    public NumberExpression(int number)
    {
        this.number = number;
    }

    public int Interpret(Context context)
    {
        return number;
    }
}

// Adım 3: NonTerminalExpression sınıfı
public class AddExpression : IExpression
{
    private IExpression left;
    private IExpression right;

    public AddExpression(IExpression left, IExpression right)
    {
        this.left = left;
        this.right = right;
    }

    public int Interpret(Context context)
    {
        return left.Interpret(context) + right.Interpret(context);
    }
}

// Adım 4: Context sınıfı
public class Context
{
    private Dictionary<string, int> variables;

    public Context()
    {
        variables = new Dictionary<string, int>();
    }

    public void SetVariable(string variable, int value)
    {
        variables[variable] = value;
    }

    public int GetVariable(string variable)
    {
        if (variables.ContainsKey(variable))
        {
            return variables[variable];
        }
        throw new ArgumentException("Variable not found: " + variable);
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Context nesnesini oluşturuyoruz.
        Context context = new Context();
        context.SetVariable("x", 5);
        context.SetVariable("y", 10);

        // Expression ağacını oluşturuyoruz.
        IExpression expression = new AddExpression(new NumberExpression(3), new NumberExpression(2));
        int result = expression.Interpret(context);
        Console.WriteLine("Result: " + result); // "Result: 5" mesajı yazdırılır.

        // Başka bir Expression ağacını oluşturuyoruz.
        IExpression expression2 = new AddExpression(new NumberExpression(2), new NumberExpression(4));
        int result2 = expression2.Interpret(context);
        Console.WriteLine("Result2: " + result2); // "Result2: 6" mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Interpreter tasarım deseni kullanılarak matematiksel ifadeleri yorumluyoruz. IExpression arayüzü, ifadeleri temsil eder ve Interpret metodu, ifadeyi yorumlamak için gereken işlemi gerçekleştirir.

NumberExpression sınıfı, sayıları temsil eder ve IExpression arayüzünü uygular. AddExpression sınıfı, iki IExpression nesnesini toplar ve IExpression arayüzünü uygular. Bu sayede, farklı ifadeleri temsil eden nesneler oluşturabilir ve bunları Context nesnesi ile ilişkilendirerek ifadeleri yorumlayabiliriz. Örnekteki Context nesnesi, değişken değerlerini ve bu değişkenlere atanmış değerleri tutar.

- Iterator Tasarım Deseni

Iterator tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir koleksiyonun elemanlarına erişmek için standart bir arabirim (interface) sağlar. Bu desen, koleksiyonun iç yapısını bilmek zorunda kalmadan elemanlarına sırasıyla erişmek için bir arayüz sunar.

Iterator tasarım deseni, koleksiyon ve iterator olmak üzere iki temel yapıya sahiptir:

  1. Iterator: Elemanlara sırasıyla erişmek için bir arabirim (interface) tanımlar. Bu arabirim, koleksiyonun iç yapısını bilmeden elemanları gezmek için gerekli metotları içerir.

  2. Aggregate (Koleksiyon): Elemanları içinde tutan bir koleksiyonu temsil eder ve bu koleksiyonun üzerinde dolaşılacak iteratoru oluşturur.

C# ile bir Iterator tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Iterator arayüzü: Elemanları sırasıyla gezerek koleksiyona erişim sağlayacak metotları içeren bir arabirim (interface) tanımlar.

  2. ConcreteIterator sınıfı: Iterator arayüzünü uygular ve koleksiyondaki elemanları sırasıyla gezmek için gerekli metotları gerçekleştirir.

  3. Aggregate arayüzü: Koleksiyonun elemanlarına erişimi sağlayacak bir arabirim (interface) tanımlar. Bu arabirim, Iterator nesnesini oluşturacak metodu içerir.

  4. ConcreteAggregate sınıfı: Aggregate arayüzünü uygular ve koleksiyondaki elemanları içerisinde tutar. Aynı zamanda Iterator nesnesini oluşturacak metodu gerçekleştirir.

İşte C# örneği ile bir Iterator tasarım deseni:

using System;
using System.Collections;

// Adım 1: Iterator arayüzü
public interface IIterator
{
    bool HasNext();
    object Next();
}

// Adım 2: ConcreteIterator sınıfı
public class MyIterator : IIterator
{
    private ArrayList list;
    private int currentIndex = 0;

    public MyIterator(ArrayList list)
    {
        this.list = list;
    }

    public bool HasNext()
    {
        return currentIndex < list.Count;
    }

    public object Next()
    {
        if (HasNext())
        {
            object item = list[currentIndex];
            currentIndex++;
            return item;
        }
        throw new IndexOutOfRangeException();
    }
}

// Adım 3: Aggregate arayüzü
public interface IAggregate
{
    IIterator GetIterator();
}

// Adım 4: ConcreteAggregate sınıfı
public class MyCollection : IAggregate
{
    private ArrayList list = new ArrayList();

    public void AddItem(object item)
    {
        list.Add(item);
    }

    public IIterator GetIterator()
    {
        return new MyIterator(list);
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        MyCollection collection = new MyCollection();
        collection.AddItem("Item 1");
        collection.AddItem("Item 2");
        collection.AddItem("Item 3");

        IIterator iterator = collection.GetIterator();

        while (iterator.HasNext())
        {
            object item = iterator.Next();
            Console.WriteLine(item);
        }
    }
}

Yukarıdaki kodda, bir Iterator tasarım deseni kullanılarak bir koleksiyonu gezerek elemanlara sırasıyla erişim sağlamaktayız. IIterator arayüzü, koleksiyon elemanlarına erişimi sağlayan metotları içerir. MyIterator sınıfı, IIterator arayüzünü uygular ve ArrayList üzerinde dolaşarak elemanlara erişimi gerçekleştirir.

IAggregate arayüzü, koleksiyonun elemanlarına erişimi sağlayacak metodu içerir. MyCollection sınıfı, IAggregate arayüzünü uygular ve elemanları ArrayList içinde tutar. Aynı zamanda IIterator nesnesini oluşturacak metodu gerçekleştirir.

Kullanım örneğinde, MyCollection üzerinden bir iterator oluşturuyoruz ve while döngüsüyle elemanlara sırasıyla erişiyoruz. Böylece koleksiyonun iç yapısını bilmemize gerek kalmadan elemanlara erişim sağlamış oluyoruz.

- Mediator Tasarım Deseni

Mediator tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve nesneler arasındaki iletişimi kolaylaştırmak için kullanılır. Bu desen, nesneler arasındaki doğrudan bağımlılığı ortadan kaldırarak, nesnelerin birbirleriyle doğrudan iletişim kurmasını engeller ve tüm iletişimi tek bir aracı nesne (mediator) üzerinden yönetir.

Mediator tasarım deseni, karmaşık bir nesne yapısı olan sistemi basit bir şekilde organize etmeyi sağlar. Bu sayede, sistemdeki nesneler arasındaki bağlantıları azaltır ve sistemdeki nesnelerin kolayca değiştirilmesini ve eklenebilmesini sağlar.

C# ile bir Mediator tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Mediator arayüzü: Sistemdeki nesneler arasındaki iletişimi sağlamak için gerekli metotları tanımlar.

  2. ConcreteMediator sınıfı: Mediator arayüzünü uygular ve nesneler arasındaki iletişimi yönetir.

  3. Colleague sınıfları: Mediator üzerinden birbirleriyle iletişim kuran nesneleri temsil eder.

İşte C# örneği ile bir Mediator tasarım deseni:

using System;

// Adım 1: Mediator arayüzü
public interface IMediator
{
    void SendMessage(string message, Colleague colleague);
}

// Adım 2: ConcreteMediator sınıfı
public class Chatroom : IMediator
{
    public void SendMessage(string message, Colleague colleague)
    {
        Console.WriteLine($"{colleague.Name} sent message: {message}");
    }
}

// Adım 3: Colleague sınıfları
public abstract class Colleague
{
    protected IMediator mediator;

    public string Name { get; }

    public Colleague(IMediator mediator, string name)
    {
        this.mediator = mediator;
        Name = name;
    }

    public virtual void Send(string message)
    {
        mediator.SendMessage(message, this);
    }

    public abstract void Receive(string message);
}

public class User : Colleague
{
    public User(IMediator mediator, string name) : base(mediator, name)
    {
    }

    public override void Receive(string message)
    {
        Console.WriteLine($"{Name} received message: {message}");
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Mediator nesnesini oluşturuyoruz.
        IMediator chatroom = new Chatroom();

        // Colleague nesnelerini oluşturuyoruz.
        Colleague user1 = new User(chatroom, "Alice");
        Colleague user2 = new User(chatroom, "Bob");

        // Colleague nesneleri arasında mesaj gönderme işlemi.
        user1.Send("Hello, Bob!"); // "Bob received message: Hello, Bob!" mesajı yazdırılır.
        user2.Send("Hi, Alice!"); // "Alice received message: Hi, Alice!" mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Mediator tasarım deseni kullanılarak basit bir sohbet uygulaması oluşturuyoruz. IMediator arayüzü, sistemdeki nesneler arasındaki iletişimi sağlayacak metotları içerir ve Chatroom sınıfı bu arayüzü uygular.

Colleague soyut sınıfı, Mediator üzerinden birbirleriyle iletişim kuracak nesneleri temsil eder ve User sınıfı bu soyut sınıfı uygular. User sınıfı, Receive metodu ile alınan mesajları işler ve Send metodu ile mesaj gönderebilir.

Kullanım örneğinde, bir Chatroom oluşturuyoruz ve User nesneleri arasında mesaj gönderme işlemi gerçekleştiriyoruz. Mesaj gönderildiğinde, Chatroom üzerinden tüm katılımcılara mesaj iletildiğini ve mesajın ilgili alıcının Receive metodu ile işlendiğini görebiliriz. Bu sayede, nesneler arasındaki bağlantıyı azaltıp iletişimi tek bir aracı üzerinden yöneterek sistemdeki esnekliği artırıyoruz.

- Memento Tasarım Deseni

Memento tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir nesnenin durumunu kaydedip geri yüklemek için kullanılır. Bu desen, bir nesnenin iç durumunu başka bir nesneye saklamak için bir aracı nesne (memento) kullanarak, nesnenin durumunun geçmiş anlamlı durumlarına geri dönebilmesini sağlar.

Memento tasarım deseni, üç temel yapıya sahiptir:

  1. Originator: Durumu kaydedilecek ve geri yüklenecek olan nesneyi temsil eder.

  2. Memento: Originator'un iç durumunu taşıyan nesneyi temsil eder.

  3. Caretaker: Memento'ları saklar ve gerektiğinde geri yükleme işlemini sağlar.

C# ile bir Memento tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Memento sınıfı: Originator'un iç durumunu tutan nesnedir.

  2. Originator sınıfı: Durumu kaydedilecek ve geri yüklenecek olan nesneyi temsil eder. Aynı zamanda Memento nesnesini oluşturan ve geri yükleme işlemini gerçekleştiren metotları içerir.

  3. Caretaker sınıfı: Memento nesnelerini saklar ve gerektiğinde geri yükleme işlemini sağlar.

İşte C# örneği ile bir Memento tasarım deseni:

using System;

// Adım 1: Memento sınıfı
public class Memento
{
    public string State { get; }

    public Memento(string state)
    {
        State = state;
    }
}

// Adım 2: Originator sınıfı
public class Originator
{
    private string state;

    public string State
    {
        get { return state; }
        set
        {
            state = value;
            Console.WriteLine("Current State: " + state);
        }
    }

    public Memento SaveState()
    {
        return new Memento(state);
    }

    public void RestoreState(Memento memento)
    {
        state = memento.State;
        Console.WriteLine("Restored State: " + state);
    }
}

// Adım 3: Caretaker sınıfı
public class Caretaker
{
    public Memento Memento { get; set; }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Originator ve Caretaker nesnelerini oluşturuyoruz.
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        // Originator'un durumunu değiştiriyoruz ve Memento nesnesini saklıyoruz.
        originator.State = "State 1";
        caretaker.Memento = originator.SaveState();

        // Originator'un durumunu değiştiriyoruz ve Memento nesnesini saklıyoruz.
        originator.State = "State 2";
        caretaker.Memento = originator.SaveState();

        // Originator'un durumunu geri yüklüyoruz.
        originator.RestoreState(caretaker.Memento); // "Restored State: State 2" mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Memento tasarım deseni kullanılarak bir nesnenin durumunu kaydedip geri yükleme işlemini gerçekleştirmekteyiz.

Memento sınıfı, Originator'un iç durumunu taşıyan nesneyi temsil eder. Originator sınıfı, durumu değiştirilecek olan nesneyi temsil eder. SaveState metodu, nesnenin durumunu kaydederek bir Memento nesnesi oluşturur. RestoreState metodu, verilen Memento nesnesini kullanarak nesnenin durumunu geri yükler.

Caretaker sınıfı, Memento nesnelerini saklar ve gerektiğinde geri yükleme işlemini sağlar. Kullanım örneğinde, Originator nesnesinin durumu değiştirilip Memento nesnesi oluşturuluyor. Daha sonra Caretaker nesnesi, bu Memento nesnesini saklayarak nesnenin durumunu geri yüklemek için kullanıyoruz. Böylece, nesnenin geçmiş durumlarına geri dönebilir ve iç durumu geçmiş anlamlı durumlar arasında kaydedebiliriz.

- Observer Tasarım Deseni

Observer tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir nesnenin durumu değiştikçe diğer nesneleri otomatik olarak güncellemek için kullanılır. Bu desen, nesneler arasındaki bağımlılıkları azaltarak, bir nesnenin durumu değiştiğinde bağımlı olan diğer nesnelerin otomatik olarak bilgilendirilmesini sağlar.

Observer tasarım deseni, iki temel yapıya sahiptir:

  1. Subject (Özne): Gözlemleyicilerin (Observer) takip ettiği ve durum değiştikçe bildirim yolladığı nesneyi temsil eder.

  2. Observer (Gözlemleyici): Subject'in (Özne) durumunu takip eden ve durum değiştikçe güncellenmek istenen nesneleri temsil eder.

C# ile bir Observer tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Subject (Özne) arayüzü: Observer nesnelerini eklemek, çıkarmak ve güncellemek için gerekli metotları içeren bir arabirim (interface) tanımlar.

  2. ConcreteSubject (ConcreteÖzne) sınıfı: Subject arayüzünü uygular ve Observer nesnelerini yöneten ve durum değiştikçe onları güncelleyen sınıftır.

  3. Observer (Gözlemleyici) arayüzü: Subject'in durumunu takip etmek ve güncellenmek isteyen Observer nesneleri için gerekli metotları içeren bir arabirim (interface) tanımlar.

  4. ConcreteObserver (ConcreteGözlemleyici) sınıfı: Observer arayüzünü uygular ve Subject'in durumunu takip eden ve güncellendiğinde tepki gösteren sınıftır.

İşte C# örneği ile bir Observer tasarım deseni:

using System;
using System.Collections.Generic;

// Adım 1: Subject (Özne) arayüzü
public interface ISubject
{
    void RegisterObserver(IObserver observer);
    void RemoveObserver(IObserver observer);
    void NotifyObservers();
}

// Adım 2: ConcreteSubject (ConcreteÖzne) sınıfı
public class WeatherStation : ISubject
{
    private List<IObserver> observers = new List<IObserver>();
    private int temperature;

    public void RegisterObserver(IObserver observer)
    {
        observers.Add(observer);
    }

    public void RemoveObserver(IObserver observer)
    {
        observers.Remove(observer);
    }

    public void NotifyObservers()
    {
        foreach (var observer in observers)
        {
            observer.Update(temperature);
        }
    }

    public void SetTemperature(int temperature)
    {
        this.temperature = temperature;
        NotifyObservers();
    }
}

// Adım 3: Observer (Gözlemleyici) arayüzü
public interface IObserver
{
    void Update(int temperature);
}

// Adım 4: ConcreteObserver (ConcreteGözlemleyici) sınıfı
public class Display : IObserver
{
    public void Update(int temperature)
    {
        Console.WriteLine("Temperature has changed: " + temperature);
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        // Subject (Özne) oluşturuyoruz.
        WeatherStation weatherStation = new WeatherStation();

        // Observer (Gözlemleyici) nesnesini oluşturuyoruz.
        IObserver display = new Display();

        // Observer'ı (Gözlemleyici) Subject (Özne) ile ilişkilendiriyoruz.
        weatherStation.RegisterObserver(display);

        // Subject'in (Özne) durumunu değiştiriyoruz.
        weatherStation.SetTemperature(25); // "Temperature has changed: 25" mesajı yazdırılır.

        // Observer'ı (Gözlemleyici) Subject (Özne) ile ilişkisini koparıyoruz.
        weatherStation.RemoveObserver(display);

        // Subject'in (Özne) durumunu tekrar değiştiriyoruz, ancak Observer artık bildirim almayacaktır.
        weatherStation.SetTemperature(30);
    }
}

Yukarıdaki kodda, bir Observer tasarım deseni kullanılarak hava durumunu takip eden bir istemci ve hava durumu öznesi oluşturulmuştur.

ISubject arayüzü, Observer nesnelerini eklemek, çıkarmak ve güncellemek için metotları içerir. WeatherStation sınıfı, ISubject arayüzünü uygular ve Observer nesnelerini yönetir. Aynı zamanda durum değiştikçe bu Observer nesnelerini günceller ve NotifyObservers metoduyla güncellemeyi bildirir.

IObserver arayüzü, Subject'in durumunu takip etmek ve güncellenmek isteyen Observer nesneleri için metotları içerir. Display sınıfı, IObserver arayüzünü uygular ve hava durumu değiştiğinde güncelleme yapılarak ekrana yazdırır.

Kullanım örneğinde, WeatherStation ile Display nesnesi arasında ilişki kurulur. Hava durumu değiştiğinde WeatherStation SetTemperature metodu çağrılarak güncelleme yapılır ve NotifyObservers metoduyla Display nesnesine güncelleme bildirilir. İlişki koparıldığında, Display nesnesine artık güncelleme bildirimi gitmez. Böylece, Observer tasarım deseni ile nesneler arasındaki bağımlılıkları azaltarak kolayca güncelleme yapabiliriz.

- State Tasarım Deseni

State tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir nesnenin durumuna göre davranışını değiştirmek için kullanılır. Bu desen, bir nesnenin farklı durumlarında farklı işlemleri gerçekleştirmesini sağlar ve böylece if-else veya switch-case gibi yapıları ortadan kaldırarak kodun daha temiz ve esnek olmasını sağlar.

State tasarım deseni, iki temel yapıya sahiptir:

  1. Context (Bağlam): Durumu değişecek olan nesneyi temsil eder ve durum nesneleri arasında geçişleri sağlar.

  2. State (Durum): Bağlam nesnesinin farklı durumlarını temsil eder ve farklı durumlarda gerçekleştirilecek işlemleri tanımlar.

C# ile bir State tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. State arayüzü: Farklı durumları temsil eden metotları içeren bir arabirim (interface) tanımlar.

  2. ConcreteState sınıfları: State arayüzünü uygular ve farklı durumlardaki davranışları gerçekleştirir.

  3. Context sınıfı: Durumu değişecek olan nesneyi temsil eder ve State nesneleri arasındaki geçişleri sağlar.

İşte C# örneği ile bir State tasarım deseni:

using System;

// Adım 1: State arayüzü
public interface IState
{
    void Handle(Context context);
}

// Adım 2: ConcreteState sınıfları
public class StateA : IState
{
    public void Handle(Context context)
    {
        Console.WriteLine("State A is handled.");
        context.State = new StateB();
    }
}

public class StateB : IState
{
    public void Handle(Context context)
    {
        Console.WriteLine("State B is handled.");
        context.State = new StateC();
    }
}

public class StateC : IState
{
    public void Handle(Context context)
    {
        Console.WriteLine("State C is handled.");
        context.State = new StateA();
    }
}

// Adım 3: Context sınıfı
public class Context
{
    public IState State { get; set; }

    public Context()
    {
        State = new StateA();
    }

    public void Request()
    {
        State.Handle(this);
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        Context context = new Context();

        // State A ile başlanır, ardından A -> B -> C -> A döngüsü oluşturulur.
        context.Request(); // "State A is handled." mesajı yazdırılır.
        context.Request(); // "State B is handled." mesajı yazdırılır.
        context.Request(); // "State C is handled." mesajı yazdırılır.
        context.Request(); // "State A is handled." mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir State tasarım deseni kullanılarak nesnenin farklı durumlarında farklı davranışlar sergilenmektedir.

IState arayüzü, farklı durumları temsil eden metotları içerir. StateA, StateB ve StateC sınıfları, IState arayüzünü uygular ve farklı durumlardaki davranışları gerçekleştirir. Her Handle metodu, durumu değiştiren ve yeni durumda geçiş sağlayan işlemleri gerçekleştirir.

Context sınıfı, durumu değişecek olan nesneyi temsil eder ve mevcut durumu tutar. Request metodu, nesnenin durumuna göre farklı davranışları gerçekleştirir ve durumu değiştirir.

Kullanım örneğinde, Context nesnesi ile başlayarak farklı durumlar arasında geçişler sağlanır ve her durumda farklı davranışlar sergilenir. Bu sayede, nesnenin durumuna bağlı olarak if-else veya switch-case gibi yapılar kullanmak yerine farklı durumları farklı sınıflarla temsil ederek kodun daha temiz ve esnek olmasını sağlarız.

- Strategy Tasarım Deseni

Strategy tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir algoritmayı bir nesne üzerinden değiştirilebilir ve seçilebilir hale getirmek için kullanılır. Bu desen, bir algoritmanın birden fazla varyasyonu olduğunda, bu varyasyonları soyutlama yoluyla nesneler aracılığıyla temsil eder ve algoritmayı çalışma zamanında değiştirmeye olanak tanır.

Strategy tasarım deseni, üç temel yapıya sahiptir:

  1. Context (Bağlam): Stratejileri kullanan nesneyi temsil eder.

  2. Strategy (Strateji): Birden fazla algoritma için arayüzü tanımlar.

  3. ConcreteStrategy sınıfları: Strategy arayüzünü uygular ve farklı algoritma varyasyonlarını içerir.

C# ile bir Strategy tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Strategy arayüzü: Farklı algoritma varyasyonları için metotları içeren bir arabirim (interface) tanımlar.

  2. ConcreteStrategy sınıfları: Strategy arayüzünü uygular ve farklı algoritma varyasyonlarını gerçekleştirir.

  3. Context sınıfı: Stratejileri kullanacak olan nesneyi temsil eder ve farklı algoritma varyasyonlarını tutar.

İşte C# örneği ile bir Strategy tasarım deseni:

using System;

// Adım 1: Strategy arayüzü
public interface ISortingStrategy
{
    void Sort(int[] array);
}

// Adım 2: ConcreteStrategy sınıfları
public class BubbleSortStrategy : ISortingStrategy
{
    public void Sort(int[] array)
    {
        Console.WriteLine("Bubble Sort");
        // Bubble sort algoritmasını uygula
    }
}

public class QuickSortStrategy : ISortingStrategy
{
    public void Sort(int[] array)
    {
        Console.WriteLine("Quick Sort");
        // Quick sort algoritmasını uygula
    }
}

// Adım 3: Context sınıfı
public class Sorter
{
    private ISortingStrategy sortingStrategy;

    public void SetSortingStrategy(ISortingStrategy strategy)
    {
        sortingStrategy = strategy;
    }

    public void Sort(int[] array)
    {
        sortingStrategy.Sort(array);
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        Sorter sorter = new Sorter();

        int[] array1 = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };
        int[] array2 = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };

        sorter.SetSortingStrategy(new BubbleSortStrategy());
        sorter.Sort(array1); // "Bubble Sort" mesajı yazdırılır.

        sorter.SetSortingStrategy(new QuickSortStrategy());
        sorter.Sort(array2); // "Quick Sort" mesajı yazdırılır.
    }
}

Yukarıdaki kodda, bir Strategy tasarım deseni kullanılarak farklı sıralama algoritmaları temsil edilmiştir.

ISortingStrategy arayüzü, farklı sıralama algoritmaları için metotları içerir. BubbleSortStrategy ve QuickSortStrategy sınıfları, ISortingStrategy arayüzünü uygular ve farklı sıralama algoritmalarını gerçekleştirir.

Sorter sınıfı, farklı sıralama algoritmalarını değiştirilebilir ve seçilebilir hale getiren Context (Bağlam) olarak görev yapar. SetSortingStrategy metodu ile sıralama algoritmasını değiştirir ve Sort metodu ile algoritmayı çalıştırır.

Kullanım örneğinde, Sorter sınıfı üzerinden farklı sıralama algoritmaları olan Bubble Sort ve Quick Sort'u uyguluyoruz. Bu sayede, sıralama algoritmasını değiştirmek için sadece SetSortingStrategy metodu çağrılarak kodun dinamik olarak davranışını değiştirmesini sağlayabiliriz.

- Template Tasarım Deseni

Template tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir algoritmanın genel yapısını tanımlar ancak bazı adımların alt sınıflar tarafından uygulanmasını sağlar. Bu desen, bir algoritmanın iskeletini oluşturan üst sınıfı tanımlar ve farklı alt sınıfların belirli adımları değiştirebileceği bir şablon sağlar.

Template tasarım deseni, iki temel yapıya sahiptir:

  1. AbstractClass (SoyutSınıf): Algoritmanın genel yapısını tanımlayan ve bazı adımları soyut metotlar olarak bırakan sınıftır.

  2. ConcreteClass (SomutSınıf): AbstractClass'ı uygular ve soyut metotları somut bir şekilde gerçekleştirir.

C# ile bir Template tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. AbstractClass: Algoritmanın genel yapısını tanımlayan soyut sınıfı oluşturur ve bazı adımları soyut metotlar olarak bırakır.

  2. ConcreteClass: AbstractClass'ı uygular ve soyut metotları somut bir şekilde gerçekleştirir.

İşte C# örneği ile bir Template tasarım deseni:

using System;

// Adım 1: AbstractClass
public abstract class Game
{
    public void Play()
    {
        Initialize();
        StartPlay();
        EndPlay();
    }

    protected abstract void Initialize();
    protected abstract void StartPlay();
    protected abstract void EndPlay();
}

// Adım 2: ConcreteClass
public class Football : Game
{
    protected override void Initialize()
    {
        Console.WriteLine("Football Game Initialized! Start playing.");
    }

    protected override void StartPlay()
    {
        Console.WriteLine("Football Game Started. Enjoy the game!");
    }

    protected override void EndPlay()
    {
        Console.WriteLine("Football Game Finished!");
    }
}

public class Basketball : Game
{
    protected override void Initialize()
    {
        Console.WriteLine("Basketball Game Initialized! Start playing.");
    }

    protected override void StartPlay()
    {
        Console.WriteLine("Basketball Game Started. Enjoy the game!");
    }

    protected override void EndPlay()
    {
        Console.WriteLine("Basketball Game Finished!");
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        Game footballGame = new Football();
        footballGame.Play();
        // Output:
        // Football Game Initialized! Start playing.
        // Football Game Started. Enjoy the game!
        // Football Game Finished!

        Game basketballGame = new Basketball();
        basketballGame.Play();
        // Output:
        // Basketball Game Initialized! Start playing.
        // Basketball Game Started. Enjoy the game!
        // Basketball Game Finished!
    }
}

Yukarıdaki kodda, Template tasarım deseni kullanılarak farklı spor oyunlarının oynanışını temsil eden bir yapı oluşturulmuştur.

Game soyut sınıfı, spor oyunlarının genel yapısını tanımlayan ve Play metodu ile oyunun sırasını belirleyen algoritmayı oluşturur. Initialize, StartPlay ve EndPlay adımları soyut metotlar olarak tanımlanır ve alt sınıflar tarafından farklı şekillerde gerçekleştirilir.

Football ve Basketball sınıfları, Game soyut sınıfını uygular ve soyut metotları somut bir şekilde gerçekleştirir. Her oyunun kendine özgü başlangıç, oyun oynama ve bitiş adımları olduğu için bu adımları farklı şekillerde uyguluyoruz.

Kullanım örneğinde, Football ve Basketball nesneleri oluşturulur ve Play metodu çağrılarak oyunların sırasıyla oynanışı simüle edilir. Bu sayede, farklı oyunların genel yapısını soyut bir sınıf üzerinden tanımlayarak kodun daha temiz ve esnek olmasını sağlayabiliriz.

- Visitor Tasarım Deseni

Visitor tasarım deseni, behavioral (davranışsal) tasarım desenlerinden biridir ve bir nesnenin yapısını değiştirmeden yeni işlevler eklemeyi sağlar. Bu desen, bir nesnenin farklı türlerinde bulunan özellikler üzerinde çalışmak için kullanılır ve işlevleri nesnelerin içine gömmek yerine, dışarıdan ayrı bir Visitor sınıfı ile gerçekleştirir.

Visitor tasarım deseni, iki temel yapıya sahiptir:

  1. Element (Öğe): Visitor nesnelerini kabul eden arayüzü veya soyut sınıfı temsil eder.

  2. ConcreteElement (SomutÖğe): Element arayüzünü uygular ve ziyaret edilecek nesneleri temsil eder.

  3. Visitor (Ziyaretçi): Elementleri ziyaret etmek için metotları içeren arayüzü veya soyut sınıfı temsil eder.

  4. ConcreteVisitor (SomutZiyaretçi): Visitor arayüzünü uygular ve Elementleri ziyaret edecek somut işlevleri gerçekleştirir.

Visitor tasarım deseni, iki aşamalı bir süreci takip eder. İlk aşamada, nesneleri ziyaret etmek için Visitor arayüzü tanımlanır ve ConcreteVisitor sınıfları bu arayüzü uygular. İkinci aşamada, ziyaret edilecek olan nesnelerin üzerinde kabul eden Element arayüzü tanımlanır ve ConcreteElement sınıfları bu arayüzü uygular.

C# ile bir Visitor tasarım deseni uygulamak için şu adımları takip edebiliriz:

  1. Element arayüzü: Visitor nesnelerini kabul eden metotları içeren bir arabirim (interface) tanımlar.

  2. ConcreteElement sınıfları: Element arayüzünü uygular ve ziyaret edilecek nesneleri temsil eder.

  3. Visitor arayüzü: Elementleri ziyaret etmek için metotları içeren bir arabirim (interface) tanımlar.

  4. ConcreteVisitor sınıfları: Visitor arayüzünü uygular ve Elementleri ziyaret edecek somut işlevleri gerçekleştirir.

İşte C# örneği ile bir Visitor tasarım deseni:

using System;

// Adım 1: Element arayüzü
public interface ICarElement
{
    void Accept(ICarVisitor visitor);
}

// Adım 2: ConcreteElement sınıfları
public class Wheel : ICarElement
{
    public void Accept(ICarVisitor visitor)
    {
        visitor.Visit(this);
    }
}

public class Engine : ICarElement
{
    public void Accept(ICarVisitor visitor)
    {
        visitor.Visit(this);
    }
}

// Adım 3: Visitor arayüzü
public interface ICarVisitor
{
    void Visit(Wheel wheel);
    void Visit(Engine engine);
}

// Adım 4: ConcreteVisitor sınıfları
public class CarElementPrintVisitor : ICarVisitor
{
    public void Visit(Wheel wheel)
    {
        Console.WriteLine("Visiting Wheel");
    }

    public void Visit(Engine engine)
    {
        Console.WriteLine("Visiting Engine");
    }
}

public class CarElementRepairVisitor : ICarVisitor
{
    public void Visit(Wheel wheel)
    {
        Console.WriteLine("Repairing Wheel");
    }

    public void Visit(Engine engine)
    {
        Console.WriteLine("Repairing Engine");
    }
}

// Kullanım örneği:
public class Program
{
    public static void Main()
    {
        ICarElement[] elements = { new Wheel(), new Engine() };

        ICarVisitor printVisitor = new CarElementPrintVisitor();
        ICarVisitor repairVisitor = new CarElementRepairVisitor();

        foreach (var element in elements)
        {
            element.Accept(printVisitor);
        }
        // Output:
        // Visiting Wheel
        // Visiting Engine

        foreach (var element in elements)
        {
            element.Accept(repairVisitor);
        }
        // Output:
        // Repairing Wheel
        // Repairing Engine
    }
}

Yukarıdaki kodda, bir Visitor tasarım deseni kullanılarak araba öğelerini (tekerlek ve motor) temsil eden bir yapı oluşturulmuştur.

ICarElement arayüzü, Visitor nesnelerini kabul eden Accept metotunu içerir. Wheel ve Engine sınıfları, ICarElement arayüzünü uygular ve Accept metotlarında ilgili ICarVisitor nesnesini çağırarak kabul işlemini gerçekleştirir.

ICarVisitor arayüzü, Elementleri ziyaret etmek için metotları içerir. CarElementPrintVisitor ve CarElementRepairVisitor sınıfları, ICarVisitor arayüzünü uygular ve Elementleri ziyaret edecek somut işlevleri gerçekleştirir.

Kullanım örneğinde, CarElementPrintVisitor ve CarElementRepairVisitor nesneleri oluşturulur ve araba öğelerini ziyaret ederken ilgili işlevleri gerçekleştirir. Bu sayede, araba öğelerinin üzerinde farklı işlemler gerçekleştirebileceğimiz ayrı Visitor sınıfları tanımlamış olduk ve nesnelerin yapısını değiştirmeden yeni işlevler eklemeyi başardık.

 

Sağlıcakla..

 



Yorumlar kapalı