Fluent Interface Örneği

Örnek Kodlar

Fluent Interface kavramı ile ilk olarak 2007 yılında  Martin Fowler’ın bu yazısını okuyunca tanışmıştım. Hatta örnekte gösterdiği

TimeInterval meetingTime = fiveOClock.until(sixOClock);

kodu beni oldukça etkilemişti. Tabi kısa bir an bir kendi yazdığım koda birde şekilde yazılan koda bakakaldım diyebilirim. Okunabilir kod deyip dururuz ya; bu kodu okuyunca “İşte okunabilir kod budur”  dediğim anlardan biridir.

Duymayanlar,bilmeyenler aslında çok fazla birşey kaçırmıyor.Fluent Interface kısaca kodun okunulabilirliğini artırmak için kullanılan bir API tasarım stili diyebiliriz. Ne tasarımınıza bir esneklik katıyor, ne de daha az kod yazmanızı sağlıyor. Amacı kodun okunulabilirliğini arttırmak ki, bence bunu da çok iyi yapıyor.

Kullandığınız birçok kütüphanede de farketmesenizde bu şekilde tasarlanmış API’ler ile karşılaştığınızı düşünüyorum. Mesela benim aklıma gelenler .NET’de kullandığım Rhino Mocks,Ninject.. Java’da kullandığım Nonblocking IO,EasyMock.. gibi birçok kütüphane bu stil ile tasarlanmış. Dikkat edecek olursanız bu kütüphanelerde yazdığınız kod aynı satırda sırayla birbirini çağıran metodlar şeklindedir.(method chaining).

İlk karşılaştığımda oldukça etkilendiğimi söylemiştim. Tabi ne zaman böyle etkilensem hemen kendi kodumda kullanmak için yer aramaya başlarım. Fakat ne kadar uğraşsamda çok fazla uygulayabileceğim yer bulamamıştım. Fluent Interface’i kodun heryerine uygulamak biraz zahmetli ve gereksiz olabiliyor. Genelde en uygun kullanım şeklinin sınıfların,kütüphanelerin konfigürasyon işlemleri olduğunu düşünüyorum.(Fluent NHibernate buna çok güzel bir örnek.).

Lafı fazla uzatmadan örneğimize dönelim.Geçenlerde geliştirdiğim bir kodda Fluent Interface şeklinde bir sınıf yazmanın oldukça faydasını gördüm sizinlede paylaşayım.

Genelde bazı uygulamalarda ekranda seçtiğiniz bir seçeneğe göre bazı alanların,girilmesi gereken kontrollerin enable,visible… olması, bazılarının ise o seçeneğe göre disable,hidden… olması gerekir. Benimde yaptığım örnek kısaca bu tarz bir uygulamaydı. ASP.NET Webforms ile geliştirilen bu uygulamada ekranda bulunan bir adet DropDownList kontrolü ile yapacağınız işlem türünü seçiyorunuz. Ardından o işlem türüne göre ekranda bazı alanlar enable, bazı alanlar disable oluyor. Vede seçtiğimiz türe göre veritabanından bazı kontrolleri dolduruyoruz,kısacası bazı işlemleride yapıyoruz.

Öncelikle akla ilk gelen yöntem seçtiğiniz kontrolün altında if-else kontrolü yapıp uygun seçeneğe göre uygun kontrolleri enable,disable edebiliriz. Fakat bu çözüm hem bu kodun diğer ekranlarda kullanılması, hemde esnekliği açısından hoş bir çözüm olmaz bu yüzden hemen aklımızdan çıkarıyoruz :)

Daha uygun olarak daha önceden bahsettiğim Table Driven Methods yöntemini kullanabiliriz. Bu şekilde if-else kontrollerinden kurtulup daha genel bir yapı tasarlamış oluruz ve bu yapıyı bu şekilde çalışan diğer ekranlarda da kullanabiliriz.

        private void ConfigureScreen()
        {
            screenState = new ScreenState();
            
            ControlState onay =new ControlState();
            onay.AddControlToEnable(pnlOnay);
            onay.AddControlToDisable(pnlItiraz);
            onay.AddControlToDisable(pnlYonlendirme);

            screenState.AddControlState(ONAY, onay);

            ControlState yonlendirme = new ControlState();
            yonlendirme.AddControlToEnable(pnlYonlendirme);
<div style="display: none"><a href='http://essay-service-best.com/'>illegal immigration essay</a></div>            yonlendirme.AddControlToDisable(pnlItiraz);
            yonlendirme.AddControlToDisable(pnlOnay);
            yonlendirme.Do(()=>BirimleriYukle());

            screenState.AddControlState(YONLENDIRME, yonlendirme);

            ControlState itiraz = new ControlState();
            itiraz.AddControlToEnable(pnlItiraz);
            itiraz.AddControlToDisable(pnlYonlendirme);
            itiraz.AddControlToDisable(pnlOnay);
            itiraz.Do(() => UrunleriYukle(false));

            screenState.AddControlState(ITIRAZ, itiraz);

            ControlState secim = new ControlState();
            secim.AddControlToDisable(pnlYonlendirme);
            secim.AddControlToDisable(pnlOnay);
            secim.AddControlToDisable(pnlItiraz);
            

            screenState.AddControlState(DEFAULT, secim);

        }

Her durum için bir ControlState sınıfı oluşturuyoruz. Ona enable,disable etmesi gereken kontrolleri veriyoruz,ardından yapması gereken işlemleri söylüyoruz. Ardından bu sınıfı ekranı temsil eden ScreenState sınıfına ekliyoruz.

ScreenState adındaki sınıfımız ekranın bütün durumlardaki durumunu simgeliyor. ControlState ise belirli bir seçim sırasındaki durumunu simgeliyor. Sınıfları şuanda çok fazla düşünmeyin. Yukarıdaki gördüğünüz koddaki okunabilirliği, ve kodun yazılım şekline dikkat etmenizi istiyorum.

Bu kodda herhangi bir problem yok gayet güzel çalışıyor. Fakat birde olaya biraz daha akıcılık katıp Fluent bir API ile yukarıdaki kodu tekrar yazalım bakalım hangisi gözümüze daha hoş gözükecek :)

        private void ConfigureScreen()
        {
            screenState = new ScreenState();

            screenState
                .WhenStateIs(ONAY)
                .EnableControls(pnlOnay)
                .DisableControls
                (
                    pnlItiraz,
                    pnlYonlendirme
                );

            screenState
                .WhenStateIs(YONLENDIRME)
                .EnableControls(pnlYonlendirme)
                .DisableControls
                (
                    pnlItiraz,
                    pnlOnay
                )
                .Do(() => BirimleriYukle());

            screenState
                .WhenStateIs(ITIRAZ)
                .EnableControls(pnlItiraz)
                .DisableControls
                (
                    pnlYonlendirme,
                    pnlOnay
                )
                .Do(() => UrunleriYukle(false));

            screenState
                .WhenStateIs(DEFAULT)
                .DisableControls
                (
                    pnlItiraz,
                    pnlOnay,
                    pnlYonlendirme
                );
        }

Yukarıdaki kodu ingilizce olarak okumaya çalışın. Mesela ikincisini sizin için ben okuyayım.Ekran durumu YONLENDIRME olduğunda pnlYonlendirme’yi enable et,pnlItiraz,pnlOnay disable et ve Birimleri yükle. Okunuşu diğerine göre daha akıcı değil mi? Peki okunuşu bizim için neden önemli?

Yukarıdaki kodda da gördüğünüz gibi Fluent Interface tekniği ile kodun okunulabilirliğini oldukça geliştirdik. Aslında küçük bir Internal DSL yaptık diyebiliriz. Uygulamamızın küçük bir bölümüne göre bir dil tasarladık yani.Fluent Interface olarak API geliştirmek için aslında çok değişik bir teknik yok. Metodların sonunda void yerine sınıfın kendisini döndürüyoruz. Bu şekilde noktadan sonra o sınıfın başka metodlarınıda çağırabiliyoruz. Özellikle sınıflara konfigürasyon yapılırken işimizi oldukça kolaylaştırdığını düşünüyorum.Fluent NHibernate bunun çok güzel bir örneği. XML konfigürasyon dosyalarından tamamen kurtulup Fluent Interface şeklinde NHibernate mapping konfigürasyonunu yapabiliyorsunuz.Fluent Interface tekniğinin aklınızın bir köşesinde bulunmasını tavsiye ederim.

5 thoughts on “Fluent Interface Örneği

  1. Enes

    Ekstradan güzel bir anlatım olmuş. Ekstradan diyorum çünkü kodun okunabilirliğini 2. kademedden geliştirme gibi bir iş yükünü de üzerime almaktan korktuğum kesin :) ama neden kodun okunabilirliğinin önemli olduğu noktasında bu ,iş yükünü almanın faydalı olabileceğini anladım. Teşekkürler Cihat hocam.

  2. Pingback: Fluent Validation ile Server-Side Validation İşlemleri | CETURK

  3. Pingback: Makinalp - » Fluent Validation ile Server-Side Validation İşlemleri

Comments are closed.