Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Intercepting Filter Pattern(Filtreleme Tasarım Deseni)

Merhaba,

Bu içeriğimizde, kullanıcıdan gelen isteği(request) işleme almadan önce filtreleyip süzgeçten geçirmemizi sağlayan ya da istek neticesinde kullanıcıya döndürülecek cevabı(response) modifiye ederek o şekilde döndürmemize imkan tanıyacak olan Intercepting Filter Pattern‘ı inceliyor olacağız.

Intercepting Filter Pattern Nedir?
Bu pattern’ı izah edebilmek için direkt olarak şöyle bir örnek üzerinden misal verebiliriz; Bir uygulamada(web, masaüstü, console, mobile vs.) kullanıcıdan gelen istek üzerine işlem yapmadan önce kullanıcının oturum açıp açmadığını kontrol etmek ve session bilgileri bulunmadığı taktirde kullanıcıya isteğin başarısız olduğunu bildirip login sayfasına yönlendirmek isteyebiliriz. Ayriyetten oturum açmışsa eğer gerekli validation kurallarını kontrol etmek ve isteği ancak bu şekilde başarılı kılmak isteyebiliriz. Bunun yanında kullanıcıya bir cevap dönerken bu cevap üzerinde de farklı modifikasyonlar gerçekleştirip o şekilde cevabı dönmek isteyebiliriz. İşte bu ve bunun gibi istek süreçlerinin basamaklı bir şekilde bölümleme gereksinimi duyulan çalışmalarda, tasarımsal açıdan Intercepting Filter Pattern‘ı uygulayarak daha pratik ve stratejik çözümler getirebiliriz.

Intercepting Filter Pattern’ın Mantığı Nedir?
Intercepting Filter Pattern’da merkezi olarak filtre görevi gören sınıflar bulunmaktadır. Bu sınıflar sıralı bir şekilde tetiklenerek işlevsellik göstermektedirler.

Intercepting Filter Pattern(Filtreleme Tasarım Deseni)

Bu mekanizmaya ‘Filter Chaining’ denmektedir.

Yukarıdaki görsel şemayı incelersek eğer her bir filtre kendi görevini yerine getirdikten sonra kontrolü kendinden sonraki filtreye bırakmaktadır. Bu süreci de yazımızın devamında ilgili pattern’ı stratejik olarak incelerken göreceğimiz üzere ‘Filter Manager‘ isimli sınıf yürütmektedir.

Filtrelerin işlevleri sırasında herhangi bir filtrede hatalı bir durum meydana gelir yahut tespit edilirse kendinden sonraki gelen filtreler devreye girmeden işlem durdurulur ve kullanıcıya duruma dair gerekli bildiride bulunulur.

Intercepting Filter Pattern, istekleri karşılayacak ve handle edecek olan temel kod üzerinde, değişikliklere ve modifikasyonlara gerek kalmaksızın ortak hizmetleri standart bir şekilde işlemek amacıyla takılabilir filtreler oluşturmamızı sağlayan bir modeldir. Bu filtreler mevcut kodu değiştirmeksizin uygulamaya eklenerek devreye sokulabilir yahut çıkarılarak nitelikleri pasifize edilebilir.

Intercepting Filter Pattern’ın Uygulanması
Intercepting Filter Pattern(Filtreleme Tasarım Deseni)Intercepting Filter Pattern’ını uygulayabilmek için yandaki şemada olduğu gibi ‘Filter Manager’, ‘Filter Chain’, ‘Filters’ ve ‘Target’ aktörlerinin kurguda yer alması gerekmektedir.

Bu aktörlerin kısaca ne olduğuna değinmemiz gerekirse eğer;

 

  • Filter Manager
    Filtre işlemeyi yöneten sınıftır. Doğru sıralamada filtre zincirini(Filter Chain) oluşturur ve işlemeyi başlatır.
  • Filter Chain
    Filtreleri belirli bir target’a özel sıralı bir şekilde listeleyen(bir başka deyişle tutan) ve tetikleyen sınıftır.
  • Filters
    Bir işe odaklanmış filtrelerdir. Bu filtrelerin sıralı bir şekilde işlenmesi filtre zinciri tarafından kontrol edilir.
  • Target
    Client tarafından talep edilen kaynaktır/servistir/işlemdir.

Pratik Örnek
Şimdi, Intercepting Filter Pattern stratejisini yukarıdaki ilk görselde verilen mantığa uygun bir senaryo üzerinden örneklendirelim. Senaryomuz; client’tan personel(EmployeeService) ve müşteri(CustomerService) bilgileri için gelen istek süreçlerinde, öncelikle kullanıcı kimlik doğrulama kontrolü(AuthenticationFilter) ve ardından validasyon kontrolü(ValidationFilter) yapılarak her iki durumun doğrulanması neticesinde istekle ilgili sonucun üretilip döndürülmesini, aksi taktirde herhangi bir filtrede oluşan aykırı duruma binaen kullanıcıyı uyararak isteğin hedef servise erişemeden iptal edilmesini gerçekleştirelim.

  • Adım 1 – Target Interface
    Herşeyden önce client’ın erişmek istediği hedef(target) servislerini inşa ederek başlayacağız. Bunun için de öncelik olarak Target Interface‘i tasarlayarak başlayalım.

        //Target Interface
        public interface ITarget
        {
            void Handler();
        }
    
  • Adım 2 – Targets
    ‘EmployeeService’ ve ‘CustomerService’ sınıflarını oluşturarak somut hedeflerimizi(concrete target) oluşturalım.

        //Concrete Target
        public class EmployeeService : ITarget
        {
            public void Handler()
                => Console.WriteLine("Employee Service Ok");
        }
    
        //Concrete Target
        public class CustomerService : ITarget
        {
            public void Handler()
                => Console.WriteLine("Customer Service Ok");
        }
    

    Burada örnek servis kodlarına dikkat ederseniz eğer içlerinde farazi olacak şekilde ekrana belirli ifadeler basılmaktadır. Tabi ki de gerçek bir senaryoda ilgili servisler ihtiyaca istinaden geliştirilecek ve gerekli davranışları sergileyecektirler.

  • Adım 3 – Filter Interface
    Artık bu adıma kadar client’ın talep edeceği hedef sınıflarımız hali hazırda mevcuttur. Bundan sonra client’tan gelecek olan talebin yaşam döngüsü sürecinde devreye girecek olan filtreleri temsil edecek olan Filter Interface arayüzünü tasarlayarak yola devam edebiliriz.

        //Filter Interface
        public interface IFilter
        {
            void Execute();
        }
    

    Sistemde kullanılacak tüm filtreler, oluşturulan bu ‘IFilter’ arayüzünü implemente etmek mecburiyetindedirler.

  • Adım 4 – Filters
    Senaryo gereği kullanıcı kimlik doğrulama kontrolünü gerçekleştirecek olan ‘Authentication Filter’ ile birlikte validasyon kontrolünü sağlayacak olan ‘Validation Filter’ sınıflarını tasarlayalım.

        //Filter
        public class AuthenticationFilter : IFilter
        {
            public void Execute()
            {
                bool isAuthenticated = Configuration.IsAuthenticated;
                if (isAuthenticated)
                    Console.WriteLine("User Authenticated");
                else
                    throw new AuthenticationException();
            }
        }
    
        //Filter
        public class ValidationFilter : IFilter
        {
            public void Execute()
            {
                bool isValidated = Configuration.IsValidated;
                if (isValidated)
                    Console.WriteLine("Validated");
                else
                    throw new ValidationException();
            }
        }
    

    Yukarıdaki filtre sınıflarını incelerseniz eğer sorumluluklarına uygun gerekli kontrolleri yaptıktan sonra ya isteğin akışına izin vermektedirler ya da aksi bir durum söz konusuysa hata fırlatarak süreci sonlandırmaktadırlar. Burada birazdan gerçekleştireceğimiz test sürecinde filtreleri daha rahat deneyebilmek için aşağıdaki ‘Configuration’ static sınıfı üzerinden değerler kontrollü bir şekilde verilmektedir.

        public static class Configuration
        {
            static public bool IsAuthenticated { get; set; }
            static public bool IsValidated { get; set; }
        }
    
  • Adım 5 – Filter Chain
    Oluşturulan bu filtreleri belirli bir hedef/target’a özel sıralı bir şekilde tutacak ve zincirleme tetikleyecek olan Filter Chain sınıfını oluşturalım.

        //Filter Chain
        public class FilterChain
        {
            readonly List<IFilter> _filters = new();
            ITarget _target;
    
            public void AddFilter(IFilter filter)
                => _filters.Add(filter);
    
            public void RemoveFilter(IFilter filter)
                => _filters.Remove(filter);
    
            public void ExecuteFilters()
            {
                _filters.ForEach(filter => filter.Execute());
                _target.Handler();
            }
    
            public ITarget Target { set => _target = value; }
        }
    

    Yukarıdaki kod bloğuna göz atarsanız eğer, belirli bir hedefe özel(_target) filtreleri ‘IFilter’ türünden olan koleksiyon(_filters) içerisinde tutmakta ve ilgili filtrelerin eklenmesi, çıkarılması ve çalıştırılması için gerekli fonksiyonları barındırmaktadır.

    Özellikle ‘ExecuteFilters’ metodunun içeriğine nazar eylerseniz eğer önce ‘_filters’ koleksiyonundaki filtreler execute edilmekte ardından ‘_target’ referansındaki hedef servis handle edilerek tetiklenmektedir. Esasında burada filtre işlev önceliği tarafımızca belirlenerek target’tan önce ya da sonra olacak şekilde çalışmalar gerçekleştirebiliriz. Haliyle bu metot, client’ın yapacağı isteğin yaşam döngüsünün işlevsel kritiğini barındıran noktadır diyebiliriz.

  • Adım 6 – Filter Manager
    Ve son olarak client’ın hedeflediği(target) servis için yapılan isteğin yaşam döngüsünde, filtre zincirini barındıran Filter Chain sınıfını yönetebilmek için Intercepting Filter Pattern’ın kalbi olan Filter Manager sınıfını tasarlayarak, oluşturalım.

        //Filter Manager
        public class FilterManager
        {
            FilterChain _filterChain;
    
            public FilterManager(ITarget target)
            {
                _filterChain = new();
                _filterChain.Target = target;
            }
    
            public void AddFilter(IFilter filter)
                => _filterChain.AddFilter(filter);
    
            public void RemoveFilter(IFilter filter)
                => _filterChain.RemoveFilter(filter);
    
            public void ExecuteFilters()
                => _filterChain.ExecuteFilters();
        }
    

    Görüldüğü üzere Filter Manager sınıfı içerisinde barındırdığı Filter Chain referansı sayesinde constructor’da aldığı target’a özel uygulanacak filtreleri yönetmekte ve execute etmektedir.

  • Adım 7 – Test
    Geliştirdiğimiz bu yapılanmayı aşağıdaki gibi bir çalışmayla teste tabi tutarsak eğer;

        class Program
        {
            static void Main(string[] args)
            {
                Configuration.IsAuthenticated = true;
                Configuration.IsValidated = true;
    
                try
                {
                    FilterManager filterManager = new(new EmployeeService());
    
                    filterManager.AddFilter(new AuthenticationFilter());
                    filterManager.AddFilter(new ValidationFilter());
    
                    filterManager.ExecuteFilters();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    

    Intercepting Filter Pattern(Filtreleme Tasarım Deseni)yandaki gibi bir ekran çıktısıyla karşılaşacağız. Nihayetinde kimlik doğrulama(IsAuthenticated) ve validasyon(IsValidated) kontrolleri için gerekli property’lere true değerini verdikten sonra(yani kısmi olarak kimliğin doğrulandığı ve validasyonların geçerli olduğunu düşünürsek), ‘FilterManager’ sınıfı üzerinden ‘EmployeeService’ isimli servise yapılan talep sürecinde eklenmiş olan ‘AuthenticationFilter’ ve ‘ValidationFilter’ filtreleri sırasıyla tetiklenmekte ve herhangi bir aksaklık olmadığından dolayı servis execute edilmektedir.

    Misal, validasyonların(IsValidated) doğrulanmadığını düşünürsek ‘ValidationFilter’da hata fırlatılacağından dolayı aşağıdaki gibi bir çıktı verilecektir;
    Intercepting Filter Pattern(Filtreleme Tasarım Deseni)

Intercepting Filter Pattern’in Faydaları Nelerdir?

  • Intercepting Filter Pattern, iyileştirilmiş yeniden kullanılabilirlik sağlar. Nihayetinde herhangi bir target’a yapılacak istek sürecinde, önceden geliştirilmiş bir filtre ihtiyaca binaen tekrar rahatlıkla kullanılabilir. Nihayetinde bir filtrenin kullanılabilirliği ‘IFilter’ arayüzü sayesinde uygulamadaki tüm target’lara genellenebileceğinden dolayı yeniden kullanılabilirlik hat safhaya çıkacaktır.
  • Intercepting Filter Pattern, filtrelerin istek süreçlerinde opsiyonel olarak eklenilip çıkarılabilmesine imkan tanıdığı için esneklik sağlamaktadır.

Ayrıca unutulmamalıdır ki, gereksiz yere uzun işlev yapan filtreler client’tan gelen isteğin yaşam döngüsünün süresini uzatacağından dolayı performans açısından zarara uğratabilir.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

1 Cevap

  1. Ali dedi ki:

    Hocam AOP gibi bir tarz gördüm burada.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir