Structural — Yapısal Desenler

Bridge

Köprü Deseni

Amaç: Bir soyutlamayı (abstraction) uygulamasından (implementation) ayırarak, ikisinin birbirinden bağımsız şekilde geliştirilebilmesini sağlamak.

1

Basit Anlatım

Teknik terim yok — günlük hayattan bir benzetme

Evinizde bir televizyon ve bir de klima var. İkisi için de kumanda kullanıyorsunuz. Basit kumanda yalnızca aç/kapa ve ses/sıcaklık tuşlarına sahip. Gelişmiş kumandada ise ek olarak sessize alma, zamanlayıcı gibi tuşlar var.

Kumanda türleri (basit, gelişmiş) ile cihaz türleri (TV, klima, radyo) iki ayrı dünyadır. Her kombinasyon için ayrı bir ürün üretseydik: "TV için basit kumanda", "TV için gelişmiş kumanda", "klima için basit kumanda"… 3 cihaz × 2 kumanda = 6 farklı ürün. Yeni bir cihaz geldiğinde 2 ürün daha!

Bunun yerine her kumanda, cihazla ortak bir "dil" (kızılötesi sinyal) üzerinden konuşur. Herhangi bir kumanda herhangi bir cihazla eşleşebilir. Aradaki o sinyal bağlantısı bir köprüdür.

Bridge şunu der: "İki farklı yönde büyüyen şeyleri birbirine kaynak yapma; aralarına bir köprü kur, her biri kendi yolunda büyüsün."
2

Teknik Anlamı

Bir yazılımcının bakış açısıyla

Bridge, kalıtım yerine composition kullanarak sınıf hiyerarşisindeki kombinasyon patlamasını önler. Bir hiyerarşi (Abstraction) diğerine (Implementor) bir referans tutar ve işi ona delege eder.

Problem: Kartezyen çarpım

Shape → Circle, Square ve renkler Red, Blue olsun. Kalıtımla RedCircle, BlueCircle, RedSquare, BlueSquare yazarsınız. Her yeni şekil veya renk sınıf sayısını çarparak artırır. Bridge ile N + M sınıf yeterlidir, N × M değil.

Katılımcılar

Adapter'dan farkı

Adapter, var olan uyumsuz sınıfları sonradan uyumlu hale getirir. Bridge ise baştan tasarlanır: iki boyutun bağımsız büyüyeceği öngörülür.

Avantajlar

3

C# ile Uygulama

Adım adım, çalışan kod örneği

Senaryo: Bir bildirim sistemi. Bildirim türleri (normal, acil) ve gönderim kanalları (e-posta, SMS, Slack) bağımsız olarak çoğalabilmeli.

Adım 1 Implementor: gönderim kanalı arayüzü ve uygulamaları

public interface IMessageSender
{
    void Send(string title, string body);
}

public class EmailSender : IMessageSender
{
    public void Send(string title, string body) =>
        Console.WriteLine($"  [E-posta] Konu: {title} | {body}");
}

public class SmsSender : IMessageSender
{
    public void Send(string title, string body) =>
        Console.WriteLine($"  [SMS] {title}: {body}");
}

public class SlackSender : IMessageSender
{
    public void Send(string title, string body) =>
        Console.WriteLine($"  [Slack #genel] *{title}* {body}");
}

Adım 2 Abstraction: bildirim hiyerarşisi

Notification, gönderim kanalını bir alan olarak tutar (köprü budur). Alt sınıflar mesajın nasıl biçimleneceğini belirler, nasıl gönderileceğini değil.

public abstract class Notification
{
    protected readonly IMessageSender Sender;   // <-- köprü

    protected Notification(IMessageSender sender) => Sender = sender;

    public abstract void Notify(string message);
}

public class NormalNotification : Notification
{
    public NormalNotification(IMessageSender sender) : base(sender) { }

    public override void Notify(string message) => Sender.Send("Bilgi", message);
}

public class UrgentNotification : Notification
{
    public UrgentNotification(IMessageSender sender) : base(sender) { }

    public override void Notify(string message)
    {
        // Acil bildirim 2 kez ve büyük harfle gönderilir.
        for (int i = 1; i <= 2; i++)
            Sender.Send($"ACİL ({i}/2)", message.ToUpper());
    }
}

Adım 3 Kullanım

Tüm parçaları bir araya getiren istemci (client) kodu:

Console.WriteLine("Normal + E-posta:");
new NormalNotification(new EmailSender()).Notify("Haftalık rapor hazır.");

Console.WriteLine("Acil + SMS:");
new UrgentNotification(new SmsSender()).Notify("Sunucu yanıt vermiyor");

Console.WriteLine("Acil + Slack:");
new UrgentNotification(new SlackSender()).Notify("Disk doldu");

Konsol çıktısı

Normal + E-posta:
  [E-posta] Konu: Bilgi | Haftalık rapor hazır.
Acil + SMS:
  [SMS] ACİL (1/2): SUNUCU YANIT VERMİYOR
  [SMS] ACİL (2/2): SUNUCU YANIT VERMİYOR
Acil + Slack:
  [Slack #genel] *ACİL (1/2)* DİSK DOLDU
  [Slack #genel] *ACİL (2/2)* DİSK DOLDU

Kodda dikkat edilmesi gerekenler

Özetle: Bridge, iki bağımsız boyutu kalıtım yerine composition ile bağlar; sınıf patlamasını önler ve her boyutun ayrı ayrı büyümesine izin verir.
← Ana sayfaya dön