Image
Kasım 09 2014 02:28

Adapter Design Pattern (ADP)

Efendim malumunuz “Adaptor” kelimesine pek yabancı sayılmayız, özellikle yurt dışı yada yurt içinde bir otelde pansiyonda kaldığımızda genelde bizim notebook yada telefon şarjına uymayan prizler ile karşılaşırız bu durumlar için bir adaptöre ihtiyaç duyarız.
Ya da cep telefonların, laptopların vb taşınabilir elektronik cihazların tamamın da kullandığımız cihaza gerekli voltajdan daha yüksek voltaj veren prizleri dize getirmek için adaptörleri kullanırız.

Benzer bir senaryo yazılım literatüründe kullanılmakta ve adına da “Adapter Design Pattern” yani “Uyarlayıcı Tasarım Deseni” kavramı denilmektedir.
Peki efendim bu tasarım, yazılım dünyasında ne işimize yarar neden kullanmak zorunda kalırız ?

  1. Elinizde bir yazılım projesi var, siz yazdınız ya da “önceki developer-lar” yazdı. Fakat eklemek istediğiniz yeni bir yapı var. Bu size ait bir sınıf olabileceği gibi, açık kaynak kodlu bir 3rd party tool yada framework te olabilir.

    İşte bu patterni, elinizde mevcut bulunan yapıya uymayan bir sınıfı/bileşeni entegre etme tekniği olarak adlandırabiliriz.

  2. Yada sınıfı birim test ya da başka amaçlar için yeni bir arayüzle çevrelemek (wrap) için kullanmak istiyor olabilirsiniz.Temelde yaptığı iş arkada tarafta sisteme yeni bir arayüz kazandırmaktan başka bir şey değildir.Peki, nasıl çalışır?
    Patternin 4 yapı taşı vardır,

1- Hedef Sınıf: Adapte olunması gereken sistem arayüz,
2- Adapter: Uyarlanmış arayüzü uygulayan sınıf
3- Adaptee: Sisteme entegre çalışması istenen parça/sınıf/bileşen
4- Client: Sistemi kullanan sınıf

Blog image

Diyagrama bakacak olursak,
Adaptor: methodA() isminde bir methoda sahip  aynı zamanda  Adeptee classını kullanıyor dolayısı ile Adaptee nin methodB() si ne de sahip.
Client : kendisi doWork() adında bir methoda sahip aynı zamanda Adaptor nesnesini kullanıyor. dolayısı ile Adaptor ün methodA() sını kullanabilir.

soru : peki biz Adaptee nin methodB() sini kullanmak istiyorsak neden araya bir Adaptor koyduk?
Çünkü
1 – Open /closed  ilkesine bağlı kalmamız gerek, sistem genişlerken değişmeme lidir.
2- Ben Clientin Adaptee yi bilmesini istemiyorum çünkü Adaptee benim sistemimin genişleme noktasıdır. Bu gün Abc Adaptee si kullanırım yarın başka bir adaptee kullanırım bu durumda Cliente ki kodları değiştirmem. Sadace yeni eklenecek olan Adaptee classı için yeni bir Adapter yazıp onu implemente ederim.

aşağıdaki örneği incelersek biraz daha anlaşılır olacaktır.

Örnek senaryo:
Elimizde bir log sistemimizin olduğunu düşünelim. Biz bu log-u kullanıyoruz ve gayet memnunuz ancak günün birinde, şartlar (bir emmi) bizi, yeni bir loglama mekanizmasını entegre etmeye zorladığında ne yapmamız gerektiğini, gelin hep birlikte görelim.

Mevcut sistem: Elimizde ILogger interfacesinden türeyen, file ve database ye yazan 2 farklı log seçeneğimiz vardır.

public interface ILogger
    {
        void WriteLog(string logText);
    }
    
    // bu sınıf file log yazar
    public class FileLogger : ILogger
    {
        public void WriteLog(string logText)
        {
            var file = new System.IO.StreamWriter("c:\\test.txt");
            file.WriteLine(logText);
            file.Close();
        }
    }
    
    // Bu fınıf database log yazar
    public class DatabaseLogger : ILogger
    {
        public void WriteLog(string logText)
        {
            //write log to db
        }
    }

Günün birinde bizden Clouda Table Bloba log yazmamız istendiğini düşünelim. CloudBlob adında bir 3rd bir tool aldık ve onun yapısı da aşağıdaki gibi olsun.

// Azure Blob Tablye loglama
   // 3rd party tool içindeki yapı
    public class CloudBlobLogger
    {
        public void WriteLogToBlog(BlobLogItem blobLogItem)
        {
            //Azure blob table log yazan kod bloğu
        }
    }

    public class BlobLogItem
    {
        public string LogId { get; set; }
        public string LogDescription { get; set; }
    }

Bu durumda Cloud Logu entegre etmek için bir adapter sınıfı yazarız.

// Adapter sınıfı
   public class LoggerAdapter:ILogger
   {
       private CloudBlobLogger _cloudBlobLogger;

       public void WriteLog(string logText)
       {
           var logItem = new BlobLogItem
           {
               LogId = Guid.NewGuid().ToString(),
               LogDescription = logText
           };
           _cloudBlobLogger= new CloudBlobLogger();
           _cloudBlobLogger.WriteLogToBlog(logItem);
       }
    }

Ve nihayet adapter clasımızı kullanıyoruz.

class Program
    {
        static void Main(string[] args)
        {
            var loggerAdapter = new LoggerAdapter();
            loggerAdapter.WriteLog("deneme");
        }
    }

Sonuç: Yazdığımız bu sınıfımız, ILogger den türeyerek mevcut sistemimizin bir parçası olur. Ancak içerisinde çalıştırdığı sistem Clod Blog Log – WriteLogToBlob mekanizmasıdır.
Artık istemci/client kodunda herhangi bir güncelleme yapmadan “Açık kapalı” prensibine uygun bir şekilde olayı çözmüş oluyoruz.
Yarın başka bir log sistemi kullanacak olsam onun içinde bir adaptor yazarım olur biter.

Aklıma gelmişken, Ado.net-i sevmeyen var mı?
evet IDataAdapter den söz ediyorum, incelemekte fayda var

Blog image

 


 

Yetmez derseniz birde :   Nuri Yılmaz : Adapter Design Pattern bakmanızı tavsiye ederim

 

2015 : memet tayanç