C# ile Dependency Injection ve Loosely Coupling

By Burak TUNGUT - 6.5.2013 - 1 Yorum - Kategori C#

Düzgün ve detaylı bir analiz yapılmadan geliştirme sürecine geçilmiş bir çok projenin eninde sonunda başvurduğu nadide yöntemlerden biridir Dependency Injection.

Dependency Injection ve Loosely Coupling Genellikle geliştirme sürecinde ihtiyaç duyulan gereksinimlere göre yapılan projelerde bir sorun görülmese de, zamanla ihtiyaçların artacağı ve sıkı bağlı tipler ile geliştirilmiş projelerde ciddi sıkıntılar yaşanabilmektedir.

Az önce güzel bir anahtar kelimeden bahsetti; sıkı bağlı!
Aslında biz bu anahtar kelimeden ziyade, bunun tam tersi ile ilgileniyor olacağız. Yani; gevşek bağlı (Loosely Coupled).

Gevşek bağlı tipler ile çalışmanın en büyük faydası projenin ilerleyen zamanlarda gelişime açık ve rahatça revize edilebilmesidir.

Konuyu ilk hakimiyeti sağlamanın en güzel yolu kanımca göresellerdir. Bunun için yandaki gibi fareye bağımlı olmuş bir insan elini örnek alabiliriz smiley

Günlük Hayattan Bir Senaryo

Bir proje yapıyor olalım. Bu projenin bir aşamasında da kullanıcının fareyi ara bir tip ile kullanması gerektiğiniz düşünelim.

Proje tahmin edileceği üzere düzgün bir şekilde analiz edilmediği için farenin hiç bozulmayacağı ya da fareden beklenen ihtiyaçların hiç değişmeyeceği düşünüldü. Bu nedenle de sokakta görülen ilk bilgisayarcıdan bir fare alındı ve kullanıcının eline tıpkı resimde olduğu gibi verildi smiley

Bir müddet sonra fark ettik ki elimizdeki fare artık bizim ihtiyaçlarımızı karşılayamıyor. Bu durumda akla gelen ilk çözüm o fareyi atıp, yerine yeni bir fare almak olacaktır. Tabi ki yazılım geliştirme ve revize işlemlerindeki süreçler ne yazık ki günlük hayattan verdiğimiz bu örnekteki gibi olmuyor blush

Senaryonun Yazılım Tarafı

Şimdi ise düşündüğümüz bu senaryoyu C# ile uygulamaya dökelim. Bunun için LogitechMouse adlı bir sınıf tasarlıyor ve içerisinde ekrana kullanılan farenin markasını yazacak Write adlı bir metod yazıyorum.

class LogitechMouse
    {
        public void Write()
        {
            Console.WriteLine("Logitech Mouse Kullanıldı");
        }
    }

Bir de mouse ile kullanıcı arasındaki entegrasyonu sağlayacak ara bir sınıf daha yazıyorum. Bu sınıfımızın adı da MouseManager şeklinde olsun ve içerisindeki Use metodu tetiklendiğin de bir adet LogitechMouse sınıfından instance alsın ve Write metodunu tetiklesin.

class MouseManager
    {
        public void Use()
        {
            LogitechMouse mouse = new LogitechMouse();
            mouse.Write();
        }
    }

Şimdide Console uygulamamızın Main metodunda MouseManager sınıfından bir instance alalım ve Use metodunu tetikleyerek, LogitechMouse ile işlemimizin yapılmasını sağlayalım.

class Program
    {
        static void Main(string[] args)
        {
            MouseManager manager = new MouseManager();
            manager.Use();
        }
    }

Şu anda herşey harika gözüküyor fakat yazdığımız kodun resmedilmiş hali biraz yukarıda sağ tarafta bulunuyor smiley Uzun lafın kısası her ne kadar şu anda işimizi gören bir kod yazmış olsakta ilerleyen zamanlarda başımız ağrıyabilir.

Gelin biraz başımızı ağırtalım. LogitechMouse ne yazık ki gelişen ve değişen dünyamıza ayak uyduramadı ve bizim için artık yetersiz konuma düştü. Artık yeni bir fare ihtiyacımız var. Biraz pazar araştırması yapıyor ve A4Tech marka bir fare satın alıyoruz. 

Yeni bir fare aldığımız için bunuda haliyle yazılım süreçleri içerisinde tasarlamamız gerekmektedir. Bunun içinde aşağıdaki gibi bir A4TechMouse adlı sınıf yazalım.

class A4TechMouse
    {
        public void Write()
        {
            Console.WriteLine("A4Tech Mouse Kullanıldı");
        }
    }

Bu kısımda başımızı ağırtacak herhangi birşey olmadı ancak bu fareyi kullanabilmek için, elimizdeki fareyi kullanmamızı sağlayan MouseManager adlı sınıfta ciddi bir değişiklik yapmamız gerekmektedir!

Bu durumda LogitechMouse sınıfından aldığımız instanceları iptal edip, yerine yeni tasarladığımız A4TechMouse adlı sınıftan instancelar almalıyız.

class MouseManager
    {
        public void Use()
        {
            //LogitechMouse mouse = new LogitechMouse();
            A4TechMouse mouse = new A4TechMouse();
            mouse.Write();
        }
    }

Her bir fare değiştirmek istediğimiz de ya da örneğimizden dışarı çıkacak olursak, sıkı bağlı tipler üzerine kurduğumuz bir projede her bir yapmak istediğimiz yenilikde yazdığımız onlarca kod heba olacak hatta büyük projelerden bahsediyorsak durum, içinden çıkılmayacak bir hal alacaktır.

Dependency Injection Yardımıyla İyileştirmeler

İşte bu durumda sıkı bağlı tipleri, Dependency Injetion ile birer gevşek bağlı tip haline getirmemiz gerekmekte. Dikkat edilirse iş katmanı olarak nitelendirebileceğimiz MouseManager adlı sınıf hangi fareyi kullanacaksak, o fareye ait tipin Write metodunun tetiklemektedir. Bin çeşit faremiz de olsa kullanacağımız sadece bir metod olduğu için fareleri baz alacak bir soyut tip üretmemiz, çözümümüzün ilk adımı olacaktır.

Bu soyutlamayı abstract sınıflar ile yapabileceğimiz gibi, interface'ler ile de yapabilir ki genellikle tercihimiz de bu yönde olmakta.

O zaman tüm farelerin implemente edeceği, aşağıdaki gibi bir interface yazalım;

interface IMouse
    {
        void Write();
    }

Kullandığımız fare tipleri için tasarladığımız sınıflarımız hali hazırda zaten mevcut. Tek yapmamız gereken tüm mouse tiplerinin IMouse adlı interface'i implemente etmeleri yani her bir farenin artık birer IMouse tipinde olması olacaktır.

Bu durumda tasarladığımız LogitechMouse ve A4TechMouse sınıfları aşağıdaki hali alacaktır;

class LogitechMouse : IMouse
    {
        public void Write()
        {
            Console.WriteLine("Logitech Mouse Kullanıldı");
        }
    }

    class A4TechMouse : IMouse
    {
        public void Write()
        {
            Console.WriteLine("A4Tech Mouse Kullanıldı");
        }
    }

Entegrasyonu sağlayan iş katmanımızda ise artık bir instance alma işlemi gerçekleştirmeyeceğiz! Bunun yerine bir üst katmandan gelecek instance'ın Write metodu tetiklenmelidir.

Ancak bu katmana hangi farenin geleceği belli değil. Ancak az önce yaptığımız iyileştirmeler sonucunda IMouse adlı bir ana (base) tip elde ettik. Bu nedenle MouseManager sınıfımız aşağıdaki hali alabilir;

class MouseManager
    {
        private readonly IMouse iMouse = null;
        public MouseManager(IMouse iMouse)
        {
            this.iMouse = iMouse;
        }
        public void Use()
        {
            iMouse.Write();
        }
    }

Mutlak suretle artık iş katmanımız kullanılmak istenilen farenin kurucu metod aracılığı ile iletilmesini istemektedir. Bu durumda her iki fareyide kullanmamızı sağlayan Main metodumuz aşağıdaki gibi olacaktır;

class Program
    {
        static void Main(string[] args)
        {
            new MouseManager(new LogitechMouse()).Use();

            new MouseManager(new A4TechMouse()).Use();
        }
    }

İzlediğimiz ve uyguladığımız bu tasarım ile artık milyonlarca faremiz dahi olsa projemizde özelliklede iş katmanında hiç bir değişiklik yapmadan yeni tiplerimizi aynen kullanabiliriz.

Yaklaşık 3 ayrı makaleden oluşacak bir yazı dizisinin başlangıcını bugün yapmış olduk. Sonraki konularda IoC ve bu formu sağlayan bazı frameworklerden bahsediyor olacağım.

 

Bir sonraki makalemde görüşmek üzere, herkese esenlikler dilerim :)
H.Burak TUNGUT

Yorum Bırak

Facebook
Son Yorumlar