Adapter (Adaptör) Design Pattern
31-05-2017 Okuma Modu
Adapter design pattern, birbiriyle ilişkili olmayan interface'lerin birlikte çalışmasına olanak sağlar. Genellikle mevcut(eski) sınıfların yapısını bozmadan diğer sınıflarla uyum içinde çalışması için uygulanır.
Çin'den yerli üretim bir telefon sipariş verdiniz ama şarj cihazı sizin evdeki prize uygun değil. Pakete dikkatli baktığınızda bir de içinden prizinize uygun adaptör çıktığını göreceksiniz. İşte bu adaptör bizim adapter pattern
'in somut örneğidir.
Daha iyi kavramak için bir örnek yapalım.
class NotificationManager
{
public function sendNotification($type = null, $data)
{
switch($type){
case "email":
$notification = new EmailService();
$notification->setTo($data['to']);
$notification->setFrom($data['from']);
$notification->setTitle($data['title']);
$notification->setMessage($data['message']);
$notification->sendEmail();
break;
case "sms":
$notification = new SmsService();
$notification->setNumber($data['number']);
$notification->setMessage($data['message']);
$notification->sendSms();
break;
}
}
}
Hali hazırda e-mail ve sms ile müşterilerie bilgilendirme yapan sistemimiz var. Patron çıldırdı, müşterileri farklı iletişim kanallarından da spamlemek istedi ve browserdan push notification atalım dedi. GCM için de class'ımızı hazırladık fakat kodlarımız giderek karmaşıklaşmaya başladı. Sms, e-mail ve push notification birbirlerinden bağımsız teknolojiler ama ortak bir amacı var müşteriye bilgi atmak.
Bizim notification manager'imizde tamamiyle bu işe adanmış. Ortak alanlar ise data almak ve alıcıya göndermek. O zaman interface'imizi aşağıdaki gibi tanımlamak gayet mantıklı olacaktır.
interface NotificationInterface
{
public function setData($data);
public function sendNotification();
}
Şimdi var olan somut sınıflara adapter somut sınıflarımızı hazırlayalım.
class SmsAdapter implements NotificationInterface
{
protected $data;
public function setData($data)
{
$this->data = $data;
}
public function sendNotification()
{
$notification = new SmsService();
$notification->setNumber($this->data['number']);
$notification->setMessage($this->data['message']);
$notification->sendSms();
}
}
class EmailAdapter implements NotificationInterface
{
protected $data;
public function setData($data)
{
$this->data = $data;
}
public function sendNotification()
{
$notification = new EmailService();
$notification->setTo($this->data['to']);
$notification->setFrom($this->data['from']);
$notification->setTitle($this->data['title']);
$notification->setMessage($this->data['message']);
$notification->sendEmail();
}
}
class FirebaseAdapter implements NotificationInterface
{
protected $data;
public function setData($data)
{
$this->data = $data;
}
public function sendNotification()
{
$notification = new FireBaseService();
$notification->setRegId($this->data['reg_id']);
$notification->setMessage($this->data['message']);
$notification->push();
}
}
Her bir somut sınıfımızın
yapısına dokunmadan adaptör sınıfını da yazdık. Şimdi bunları NotificationManager
de kullanalım.
class NotificationManager
{
public function sendNotification($type = null, $data)
{
switch($type){
case "email":
$notification = new EmailAdapter();
break;
case "sms":
$notification = new SmsAdapter();
break;
case "firebase":
$notification = new FirebaseAdapter();
break;
default:
die("Unknown type");
}
$notification->setData($data);
$notification->sendNotification();
}
}
Adapter pattern için her şey yolunda ama bir dakika SOLID
prensiplerine aykırı bir durum var. Ben her ekleyeceğim notification kanalı için bir koşul mu yazacağım yada kullanmaktan vazgeçtiğimde koşulumu sileceğim. Tabi ki hayır.
Adapter somut sınıflarımı interface üzerinden implement
ettiğim için interface üzerinden oluşturabilirim. Hadi son haline bakalım.
class NotificationManager {
public function sendNotification(NotificationInterface $notification, $data)
{
$notification->setData($data);
$notification->sendNotification();
}
}
Kendinize iyi bakın :)