Teknik Detaylar

Facade Tasarım Deseni Nedir?

← Teknik Detaylar
2021-09-13 · 5 dk okuma
Facade Tasarım Deseni Nedir?
Bu yazıyı yapay zekâ ile tartış
Sayfayı kopyala

Bu yazı Design Patterns/Tasarım Desenleri Nedir? başlıklı yazı dizisinin bir parçasıdır.

Bu içerik ağırlıklı olarak refactoring.guru sitesindeki içeriğin tercümesi ve derlenmesinden oluşturulmuştur.

Tüm tasarım desenleri ya da diğer adıyla tasarım kalıplarına yönelik ayrıntılı içeriklere yazının sonundaki bağlantılardan ulaşabilirsiniz.

💡 Özet (TL;DR):

  • Amaç: Çok sayıda karmaşık sınıftan oluşan bir alt sisteme (subsystem), kullanımı kolay basitleştirilmiş tek bir giriş kapısı (arayüz) sağlar.
  • Kilit Yapılar: Önyüz Sınıfı (Facade) ve Alt Sistem Sınıfları (Subsystems).
  • Avantajları: İstemci kodun alt sisteme olan bağımlılığını (tight coupling) azaltır. Kodun okunabilirliğini ve bakımını kolaylaştırır.

Facade Tasarım Deseninin Amacı

Facade (Önyüz), bir kütüphane, framework ya da karmaşık sınıflardan oluşan bir alt sistem için basitleştirilmiş bir arayüz sunan yapısal (structural) bir tasarım desenidir.


Sorun

Kodunuzu karmaşık bir kütüphane veya framework içerisindeki onlarca nesneyle çalışacak şekilde tasarlamanız gerektiğini düşünün. Normal şartlarda bu nesnelerin tamamını başlatmanız (initialize), bağımlılıklarını yönetmeniz ve metotları doğru sırada çalıştırmanız gerekir.

Bu durumda, yazmış olduğunuz kendi sınıflarınızın iş mantığı, üçüncü parti kütüphanelerin sınıflarına sıkı sıkıya bağlı (tightly coupled) hale gelecektir. Bu da kodun anlaşılmasını, test edilmesini ve gelecekte yönetilmesini zorlaştırır.


Çözüm

Facade, birçok değişken parça içeren karmaşık bir sisteme basit bir giriş arayüzü sunan bir sınıftır. Alt sisteme doğrudan erişmeye kıyasla daha sınırlı ve özelleştirilmiş bir işlevsellik sağlar, ancak istemcilerin en çok ihtiyaç duyduğu özellikleri tek bir çatı altında toplar.

Bir kütüphanenin sadece çok küçük bir özelliğine ihtiyaç duyduğunuzda Facade harika iş çıkarır.

Örneğin, sosyal medyaya video yükleyen basit bir uygulama yaptığınızı varsayalım. Arka planda onlarca ayarı ve parametresi olan devasa bir video dönüştürme (encoding) kütüphanesi kullanıyorsunuz. İstemcinin tüm bu detaylarla boğuşması yerine, sadece encode(filename, format) metoduna sahip bir VideoConverterFacade sınıfı yazarız. Bu sınıf karmaşık kütüphaneyi arka planda başlatır ve yönetir. İstemci ise sadece bu Facade ile konuşur.


Gerçek Hayat Senaryosu: E-Ticaret Sipariş İşlemleri (Checkout)

Bir sipariş checkout süreci; stok kontrolü, ödeme tahsilatı, kargo gönderimi ve bildirim gönderimi gibi birçok bağımsız servisin çalışmasını gerektirir:

// 1. Alt Sistemler (Subsystems)
class InventoryService {
    public function checkStock(int $productId): bool { return true; }
}

class PaymentService {
    public function charge(int $customerId, int $amount): void {
        echo "Ödeme alındı.\n";
    }
}

class ShippingService {
    public function createShipment(int $productId): void {
        echo "Kargo kaydı oluşturuldu.\n";
    }
}

// 2. Facade Sınıfı (Orkestrasyonu üstlenir)
class OrderProcessingFacade {
    private InventoryService $inventory;
    private PaymentService $payment;
    private ShippingService $shipping;

    public function __construct() {
        $this->inventory = new InventoryService();
        $this->payment = new PaymentService();
        $this->shipping = new ShippingService();
    }

    public function placeOrder(int $customerId, int $productId, int $amount): void {
        if ($this->inventory->checkStock($productId)) {
            $this->payment->charge($customerId, $amount);
            $this->shipping->createShipment($productId);
            echo "Sipariş başarıyla tamamlandı!\n";
        }
    }
}

Facade vs Mediator vs Adapter vs Proxy

DesenAmaçAlt Sistem İlişkisi
FacadeKarmaşık alt sistemleri tek ve basit bir arayüzle sunmak.Alt sistem Facade'in varlığından habersizdir.
MediatorNesneler arası iletişimi merkezileştirip kaosu önlemek.Nesneler sadece Mediator ile konuşur, birbirini bilmez.
AdapterUyumsuz bir arayüzü uyumlu hale getirmek.Genelde tek bir nesneyi sarar (dönüştürür).
ProxyGerçek nesneye erişimi kontrol etmek (caching, auth vb.).Gerçek nesne ile aynı arayüze sahiptir.

Uygulanabilirlik

  • Basit Arayüz İhtiyacı: Karmaşık ve çok sayıda sınıftan oluşan bir alt sisteme sınırlı ama kullanımı kolay bir geçiş noktası sağlamak istediğinizde kullanın.
  • Katmanlı Mimari (Decoupling): Alt sistemleri katmanlara ayırmak ve katmanlar arasındaki geçişleri sadece belirli Facade kapıları üzerinden yaparak bağımlılıkları en aza indirmek istediğinizde kullanın.

Diğer Tasarım Desenleri ile İlişkisi

  • Facade mevcut nesneler için yeni bir arayüz tanımlarken, Adapter mevcut bir arayüzü kullanılabilir hale getirmeye çalışır.
  • Alt sistem nesnelerinin sadece oluşturulma aşamalarını istemci koddan gizlemek istiyorsanız Abstract Factory, Facade'e bir alternatif veya yardımcı olarak kullanılabilir.
  • Facade'ler kompleks nesnelerle çalışırken ara tampon görevi görmeleri yönüyle Proxy'lere benzerler. Ancak Proxy, servis nesnesi ile birebir aynı arayüze sahiptir.

Facade Tasarım Deseni Kod Örnekleri

Örnek PHP Kodu

<?php

namespace RefactoringGuru\Facade\Conceptual;

class Facade
{
    protected Subsystem1 $subsystem1;
    protected Subsystem2 $subsystem2;

    public function __construct(
        ?Subsystem1 $subsystem1 = null,
        ?Subsystem2 $subsystem2 = null
    ) {
        $this->subsystem1 = $subsystem1 ?: new Subsystem1();
        $this->subsystem2 = $subsystem2 ?: new Subsystem2();
    }

    public function operation(): string
    {
        $result = "Facade alt sistemleri hazırlıyor:\n";
        $result .= $this->subsystem1->operation1();
        $result .= $this->subsystem2->operation1();
        $result .= "Facade alt sistemlere komut veriyor:\n";
        $result .= $this->subsystem1->operationN();
        $result .= $this->subsystem2->operationZ();

        return $result;
    }
}

class Subsystem1
{
    public function operation1(): string
    {
        return "Subsystem1: Hazır!\n";
    }

    public function operationN(): string
    {
        return "Subsystem1: Başla!\n";
    }
}

class Subsystem2
{
    public function operation1(): string
    {
        return "Subsystem2: Hazırlan!\n";
    }

    public function operationZ(): string
    {
        return "Subsystem2: Ateşle!\n";
    }
}

function clientCode(Facade $facade)
{
    echo $facade->operation();
}

$subsystem1 = new Subsystem1();
$subsystem2 = new Subsystem2();
$facade = new Facade($subsystem1, $subsystem2);
clientCode($facade);

Örnek Python Kodu

from __future__ import annotations

class Facade:
    def __init__(self, subsystem1: Subsystem1 | None = None, subsystem2: Subsystem2 | None = None) -> None:
        self._subsystem1 = subsystem1 or Subsystem1()
        self._subsystem2 = subsystem2 or Subsystem2()

    def operation(self) -> str:
        results = []
        results.append("Facade alt sistemleri hazırlıyor:")
        results.append(self._subsystem1.operation1())
        results.append(self._subsystem2.operation1())
        results.append("Facade alt sistemlere komut veriyor:")
        results.append(self._subsystem1.operation_n())
        results.append(self._subsystem2.operation_z())
        return "\n".join(results)


class Subsystem1:
    def operation1(self) -> str:
        return "Subsystem1: Hazır!"

    def operation_n(self) -> str:
        return "Subsystem1: Başla!"


class Subsystem2:
    def operation1(self) -> str:
        return "Subsystem2: Hazırlan!"

    def operation_z(self) -> str:
        return "Subsystem2: Ateşle!"


def client_code(facade: Facade) -> None:
    print(facade.operation(), end="")


if __name__ == "__main__":
    subsystem1 = Subsystem1()
    subsystem2 = Subsystem2()
    facade = Facade(subsystem1, subsystem2)
    client_code(facade)

Sıkça Sorulan Sorular (FAQ)

Facade sınıfı kendi içinde ek bir iş mantığı (business logic) barındırmalı mıdır?

Hayır. Facade'in tek sorumluluğu, alt sistemleri istemci adına orkestre etmek ve doğru sırayla çağırmaktır. Facade sınıfına doğrudan iş mantığı eklenirse, bu sınıf zamanla büyüyerek kendisi bir "God Class" (aşırı yüklenmiş sınıf) haline gelir ve desenin amacına aykırı olur.

Alt sistemler (Subsystems) Facade sınıfına bağımlı mıdır?

Kesinlikle hayır. Alt sistemdeki sınıflar Facade'den tamamen habersizdir. Facade olmadan da doğrudan istemci kodlar tarafından başlatılabilir ve kullanılabilirler. Facade sadece dışarıdan gelen istekleri alt sistemlere dağıtan tek yönlü bir geçittir.

Facade sınıfları neden genellikle Singleton olarak tasarlanır?

Çoğu senaryoda tüm uygulama genelinde alt sisteme erişim sağlayan tek bir Facade örneği (instance) yeterlidir. Gereksiz yere birden fazla Facade nesnesi oluşturup hafıza harcamamak adına, bu sınıflar sıklıkla Singleton deseniyle birleştirilir.


Diğer Tasarım Kalıpları/Design Patterns

Oluşumsal Kalıplar (Creational Patterns)

Factory Method, Abstract Factory, Builder, Prototype, Singleton

Yapısal Kalıplar (Structural Patterns)

Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy

Davranışsal Kalıplar (Behavioral Patterns)

Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor