Adapter Tasarım Deseni Nedir?

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ç: Birbiriyle uyumsuz arayüzlere (interface) sahip iki farklı sınıfın, aralarında bir "tercüman" görevi üstlenen adaptör nesnesi aracılığıyla uyum içinde çalışmasını sağlar.
- Kilit Yapılar: Hedef Arayüz (
Target), Uyumsuz Sınıf (Adaptee), Adaptör (Adapter).- Sınıf vs Nesne Adaptörü: Sınıf adaptörleri kalıtım (inheritance) yoluyla çalışırken, nesne adaptörleri kompozisyon (composition) kullanarak hedef nesneyi sarmalar.
Adapter Deseninin Amacı
Adapter (Adaptör), birbiriyle uyumlu olmayan arayüzlere sahip nesnelerin birlikte çalışabilmelerini sağlayan yapısal (structural) bir tasarım desenidir.
Sorun
Hisse senedi piyasalarını takip etmeyi sağlayan bir uygulama geliştirdiğinizi düşünün. Uygulamanız piyasa verilerini farklı kaynaklardan XML formatında çekiyor ve daha sonra güzel görünümlü grafikler ve diyagramlar ile kullanıcıya sunuyor olsun.
Günün birinde üçüncü parti bir analiz kütüphanesi entegre ederek uygulamayı daha da geliştirmeye karar verdiniz. Yalnız bir sorun var, bu analiz kütüphanesi yalnızca JSON formatı ile çalışabiliyor.

Kütüphaneyi XML ile çalışabilecek hale getirmek için kütüphanenin kodunu değiştirmeyi düşünebilirsiniz. Ancak kütüphanenin kaynak koduna erişiminiz olmayabilir veya yapacağınız değişiklikler gelecekte kütüphaneye gelecek güncellemeleri almanızı imkansız kılabilir. Sonuç olarak, uyumsuz iki yapıyı doğrudan birbirine bağlayamazsınız.
Çözüm
Uyumsuz arayüzleri çözmek için bir Adaptör (Adapter) yazabilirsiniz. Bu özel nesne, bir nesnenin arayüzünü değiştirerek diğer nesnenin anlayabileceği bir formata dönüştürür.
İş yapmak isteyen bir Japon ve bir Alman arasında her iki dili bilen bir tercümanın yaptığı işe benzer bir rol üstlenir. Adaptör, arka tarafta dönen karmaşık dönüştürme işlemlerini gizlemek için nesnelerden birini tamamen sarmalar (wrapper).
Adaptörlerin çalışma mantığı şu adımlardan oluşur:
- İstemci, adaptör tarafından sunulan hedef arayüz (Target) metotlarını çağırır.
- Adaptör, gelen istekleri sarmaladığı uyumsuz nesnenin (Adaptee) anlayabileceği formata çevirir.
- Sonucu tekrar istemcinin beklediği formata dönüştürerek geri döndürür.

Hisse piyasası uygulamamızda, analitik kütüphanesini kullanabilmek için bir XML-to-JSON adaptörü yazarız. Bu adaptör istemciden XML verisini alır, arka planda JSON formatına dönüştürür ve analiz kütüphanesinin ilgili metotlarına bu JSON verisini besler.
Gerçek Hayat Senaryosu: Eski ve Yeni Log Sistemi Entegrasyonu
Yazılım projelerinde sıklıkla eski (legacy) kütüphaneleri yeni tanımlanan modern arayüzlere uydurmak için adaptör yazarız:
// 1. Hedef Arayüz (Target Interface) - Sistemimizin beklediği yeni yapı
interface LoggerInterface {
public function logInfo(string $message): void;
}
// 2. Uyumsuz Sınıf (Adaptee) - Kodunu değiştiremediğimiz eski loglama sınıfı
class LegacyLogger {
public function writeToDisk(string $text, int $priority): void {
echo "Disk Log ($priority): $text\n";
}
}
// 3. Adaptör Sınıfı (Adapter) - Nesne kompozisyonu kullanarak aradaki uyumu sağlar
class LegacyLoggerAdapter implements LoggerInterface {
private LegacyLogger $legacyLogger;
public function __construct(LegacyLogger $legacyLogger) {
$this->legacyLogger = $legacyLogger;
}
public function logInfo(string $message): void {
// Eski kütüphanenin metodunu çağırıp parametreleri adapte ediyoruz
$this->legacyLogger->writeToDisk($message, 1);
}
}
Adapter vs Proxy vs Facade vs Decorator
| Desen | Amaç | Arayüz Etkisi |
|---|---|---|
| Adapter | İki uyumsuz yapıyı birleştirmek. | Arayüzü uyumlu bir yeni arayüze dönüştürür. |
| Proxy | Erişim kontrolü, caching veya gecikmeli yükleme sağlamak. | Arayüzü aynı tutar. |
| Facade | Karmaşık alt sistemleri kolay yönetilebilir tek bir kapıdan sunmak. | Sistemi basitleştiren yeni ve sade bir arayüz sunar. |
| Decorator | Nesneye dinamik olarak yeni sorumluluklar eklemek. | Arayüzü değiştirmeden genişletir. |
Sınıf Adaptörü vs Nesne Adaptörü
Adaptör deseni iki farklı şekilde uygulanabilir:
1. Nesne Adaptörü (Object Adapter)
Kompozisyon (composition) ilkesine dayanır. Adaptör, adapte edilecek nesnenin (Adaptee) bir referansını kendi içinde saklar ve onu sarmalar. PHP gibi tekli kalıtım (single inheritance) destekleyen dillerde bu yöntem kullanılır ve en esnek yaklaşımdır.
2. Sınıf Adaptörü (Class Adapter)
Kalıtım (inheritance) ilkesine dayanır. Adaptör hem hedef sınıftan hem de adapte edilecek sınıftan aynı anda türetilir (çoklu kalıtım). Python ve C++ gibi çoklu kalıtımı (multiple inheritance) destekleyen dillerde uygulanabilir. Nesneyi sarmalamak yerine doğrudan metotları ezerek çalışır.
Uygulanabilirlik
- Uyumsuz Üçüncü Parti Kütüphaneler: Mevcut bir sınıfı kullanmak istediğinizde, ancak o sınıfın arayüzü kodunuzun geri kalanıyla doğrudan uyumlu olmadığında ara katman olarak kullanın.
- Yeniden Kullanılabilirlik: Ortak bir arayüze sahip olmayan veya gelecekte değiştirilmesi muhtemel eski bileşenleri sisteme entegre ederken kullanın.
Diğer Tasarım Desenleri ile İlişkisi
- Bridge tasarım aşamasında soyutlama ile uygulamayı birbirinden ayırmak için (önceden) kurulur. Adapter ise mevcut, bitmiş sistemlerin uyumsuzluğunu gidermek için (sonradan) eklenir.
- Adapter sarmaladığı nesne için farklı bir arayüz sunarken, Proxy aynı arayüzü korur. Decorator ise zenginleştirilmiş/geliştirilmiş bir arayüz sağlar.
Adapter Tasarım Deseni Kod Örnekleri
Örnek PHP Kodu (Nesne Adaptörü)
<?php
namespace RefactoringGuru\Adapter\Conceptual;
class Target
{
public function request(): string
{
return "Target: Varsayılan hedef davranışı.";
}
}
class Adaptee
{
public function specificRequest(): string
{
return ".eetpadA eht fo roivaheb laicepS";
}
}
class Adapter extends Target
{
private Adaptee $adaptee;
public function __construct(Adaptee $adaptee)
{
$this->adaptee = $adaptee;
}
public function request(): string
{
// Gelen ters veriyi düz çevirip istemciye sunuyoruz
return "Adapter: (ÇEVİRİLDİ) " . strrev($this->adaptee->specificRequest());
}
}
function clientCode(Target $target)
{
echo $target->request();
}
echo "İstemci: Target nesneleri ile sorunsuz çalışabiliyorum:\n";
$target = new Target();
clientCode($target);
echo "\n\n";
$adaptee = new Adaptee();
echo "İstemci: Adaptee sınıfının arayüzü uyumsuz, doğrudan çağıramıyorum:\n";
echo "Adaptee: " . $adaptee->specificRequest();
echo "\n\n";
echo "İstemci: Adaptör aracılığıyla çalıştırıyorum:\n";
$adapter = new Adapter($adaptee);
clientCode($adapter);
Örnek Python Kodu (Sınıf Adaptörü - Çoklu Kalıtım)
class Target:
def request(self) -> str:
return "Target: Varsayılan hedef davranışı."
class Adaptee:
def specific_request(self) -> str:
return ".eetpadA eht fo roivaheb laicepS"
class Adapter(Target, Adaptee):
# Çoklu kalıtım ile her iki sınıfın da yeteneklerini devralıyoruz
def request(self) -> str:
return f"Adapter: (ÇEVİRİLDİ) {self.specific_request()[::-1]}"
def client_code(target: Target) -> None:
print(target.request(), end="")
if __name__ == "__main__":
print("İstemci: Target nesneleri ile çalışıyorum:")
target = Target()
client_code(target)
print("\n")
adaptee = Adaptee()
print("İstemci: Adaptee uyumsuz arayüze sahip:")
print(f"Adaptee: {adaptee.specific_request()}", end="\n\n")
print("İstemci: Çoklu kalıtım tabanlı Sınıf Adaptörü ile çalıştırıyorum:")
adapter = Adapter()
client_code(adapter)
Sıkça Sorulan Sorular (FAQ)
Sınıf Adaptörü (Class Adapter) ile Nesne Adaptörü (Object Adapter) arasındaki fark nedir?
- Sınıf Adaptörü: Kalıtım kullanır. Adaptee'yi miras aldığı için onun tüm protected ve public metotlarına doğrudan erişebilir. Çoklu kalıtım gerektirir.
- Nesne Adaptörü: Kompozisyon kullanır. Adaptee nesnesini constructor üzerinden referans olarak alır. Çoklu kalıtım gerektirmediği için tüm OOP dillerinde çalışır ve runtime sırasında farklı adaptee nesneleriyle eşleşebilir.
Adapter deseni Single Responsibility Principle (SRP) ile nasıl uyuşur?
Sisteminizin ana iş mantığı ile verilerin farklı kütüphanelerin formatına (JSON, XML vb.) dönüştürülme sorumluluğu birbirinden ayrılır. Tüm dönüştürme işi sadece adaptör sınıfına verilir, böylece ana kodunuz temiz kalır.
İki Yönlü Adaptör (Two-way Adapter) nedir?
Hem Target arayüzünü Adaptee arayüzüne, hem de tam tersi Adaptee arayüzünü Target arayüzüne dönüştürebilen çift taraflı çalışan adaptörlerdir. Genellikle her iki sınıfın da arayüzünü uygulayarak yazılır.
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
