Skip to content

Latest commit

 

History

History
134 lines (100 loc) · 7.29 KB

File metadata and controls

134 lines (100 loc) · 7.29 KB

Adapter Pattern, birbiri ile uyumsuz interface'lere sahip class'ların uyumlu bir şekilde çalışması için birbirlerine adapte olmasını sağlar. Bu pattern, bir sınıfın arayüzünü, beklenen başka bir arayüze çevirir. Böylece birbirleriyle uyumsuz olan sınıflar, birlikte çalışabilir.

Örneğin yazlık araba lastiği ile kışın dağa çıkılıyor. yaz lastiği kışın buzlu ve karlı koşullara uyumsuz olduğundan kaynaklı yeterince sürtünme sağlayamayacağı için yol tutuşu sağlıklı olmayacaktır. Bu durumda, aracın lastiğine zincir veya lastik çorabı gibi "Adaptörler" takarak lastikleri ortam koşullarına uygun hale getirebilir ve kışın kullanılabilir hale çevrilebilir.

Bir diğer örnek, Avrupa, Amerika, Birleşik Krallık gibi bölgelerde elektrik prizlerinin tipleri değişiklik göstermektedir. Avrupa tipli bir kablonun Amerika soketine uyumlu olmadığından direkt olarak takılamamaktadır ancak bir Adaptör/Dönüştürücü sayesinde kullanılabilir hale çevrilebilmektedir.

Yazılımlarda Adapter, bir diğer adıyla Wrapper, mevcut sistemi değiştirmeden yeni özellikler ekleyebilmek, Eski kodları yenilemek zorunda kalmamak, Farklı kütüphaneleri veya API'ları custom projelere adapte etmek gibi çeşitli alanlarda kullanılmaktadır.

Bu yazıda, Adapter Pattern iki örnek üzerinden anlatılacaktır.

Gang of Four Design Patterns Kitabındaki Diyagram

GoFAdapterDiagram

Yukarıdaki görsel üzerinden implementasyon yapılacak olursa Target interface'i aşağıdaki gibi implemente edilir.

public interface ITarget
{
    void Request<T>();
}

Bu interface, custom uygulamada yapılacak işlemleri kullanma biçimi olarak tanımlanmaktadır. Bu biçim Adaptee class'ında bulunmadığından kaynaklı custom uygulama ile Adaptee class'ının uyumsuz olduğu buradan anlaşılmaktadır.

public class Adaptee
{
    public void SpecificRequest(string name)
    {
        Console.WriteLine($"Adaptee: {name} isimli class çağırıldı.");
    }
}

Adaptee class'ı ilgili implementasyonda string bir argument almaktadır ancak custom uygulamada sadece generic bir fonksiyon bulunmaktadır. Bu iki sistemi birbirine bağlayabilmek için bir Adapter class yazıp içeride custom uygulamaya uygun bir implementasyon yapılarak aralarındaki uyumsuzluk giderilmektedir.

public class Adapter : ITarget
{
    private readonly Adaptee _adaptee;
    public Adapter(Adaptee adaptee)
    {
        _adaptee = adaptee;
    }

    public void Request<T>()
    {
        _adaptee.SpecificRequest(typeof(T).Name);
    }
}

program.cs

internal class Program
{
    private static void Main(string[] args)
    {

        Adaptee adaptee = new Adaptee();
        ITarget target = new Adapter(adaptee);

        target.Request<Program>();
    }
}

Çıktı

Adaptee: Program isimli class çağırıldı.

CAP Kütüphanesinin Custom Bir Projeye Entegrasyonu

CAP kütüphanesi, AMQP protocolü kullanarak outbox pattern ile implemente edilmiş distributed pub/sub mekanizması sunar. Bu mekanizmayı custom uygulamada kullanılması sırasında, uygulamanın isterleri içerisinde class bazlı bir pub/sub mekanizması kullanılması istenmektedir. CAP bu mekanizmayı sağlamayıp sadece static string değerler ile işlemini yürütmektedir.

Bunun için öncelikle ITarget görevi görecek olan ICapTarget interface'i implemente edildi.

public interface ICapTarget
    {
        Task PublishAsync<T>(T message, CancellationToken cancellationToken) where T : MessageBase;
    }

Bu interface publish işlemlerinde kullanılacak argument'ın generic parameter olarak alınması gerektiğini ve bu parametrenin MessageBase class'ından türemesi gerektiğini ifade etmektedir.

public class MessageBase { }
public class CapAdapter : ICapTarget
{
    private readonly ICapPublisher _capPublisher;
    private readonly IEmopLogger _emopLogger;

    public CapAdapter(ICapPublisher capPublisher, IEmopLoggerFactory emopLoggerFactory)
    {
        _capPublisher = capPublisher;
        _emopLogger = emopLoggerFactory.ForContext<CapAdapter>();
    }

    public async Task PublishAsync<T>(T message, CancellationToken cancellationToken) where T : MessageBase
    {
        _emopLogger.Information($"Publishing message inside Cap Adapter with factory: {typeof(T).Name}");

        await _capPublisher.PublishAsync(typeof(T).Name, contentObj: message, cancellationToken: cancellationToken);
    }
}

Yukarıdaki kodda görüldüğü üzere, ICapPublisher ile gelen PublishAsync methodu string bir name, content ve cancellationToken almaktadır. Önceden bahsedildiği üzere, custom uygulamadaki isterleri karşılayacak şekilde generic parametrenin tipinin name değerini gelen methoda gönderilerek ve message'ın kendisini de içine verilerek custom uygulamayla uyumlu bir şekilde capPublisher'ı kullanılmış olmaktadır. Böylece adapter pattern uygulanmış olup iki interface arasında uyumsuzluklar giderilip kullanılmış olundu. Burada ek olarak loglama da yapılmıştır ancak bu işlem iki interface arasındaki uyumsuzluk problemini çözmediği için Adapter Pattern bazında rol almamaktadır.

CAP kütüphanesi özelinde yukarıdaki kodların çalışabilmesi için çeşitli konfigurasyonlar, service registrationlar ve implementasyonlar yapılması gerekmektedir. Bunlara buradan ulaşılabilir. ve kullanımına da consumer ve publish edildiği kısıma ulaşılabilir.

Kaynakça

Ücretsiz:

Ücretli: