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

Bağımlılığın Ters Çevrilmesi Prensibi(Dependency Inversion Principle – DIP)

Bağımlılığın Ters Çevrilmesi Prensibi(Dependency Inversion Principle - DIP)

Merhaba,

Önceki yazılarımda SOLID prensiplerinden STek Sorumluluk Prensibi(Single Responsibility Principle – SRP)‘ni, OAçık Kapalı Prensibi(Open Closed Principle – OCP)L-Liskov’un Yerine Geçme Prensibi(Liskov Substitution Principle – LSP) ve IArayüz Ayrım Prensibi(Interface Segregation Principle – ISP) incelemiştik. Bu içeriğimizde ise sıradaki ve sonuncu olan D harfine denk gelen Bağımlılığın Ters Çevrilmesi Prensibi(Dependency Inversion Principle – DIP) ele alacağız.

Dependency Inversion prensibine göre yazdığımız program soyutlama üzerine dayandırılmalıdır, katılaştırma üzerine değil.

İçeriğimize böyle bir giriş yapmayı uygun gördüm. Bunun sebebi, tasarladığımız kodun bağımlılığı implementation(uygulama) Class’lara değil, Interface’lere olması gerektiğini makalemizin başında vurgulamaktır.

Daha açık bir şekilde ifade etmek gerekirse, üst seviye sınıflar alt seviye sınıf implementasyonlarını değil Interface uygulamalarını kullanmalıdırlar.

Neden mi?
Üst seviyeli işlem yapan sınıflar(High Level Class – Yüksek Dereceli Sınıf), alt seviyeli işlem yapan sınıflara(Low Level Class – Düşük Dereceli Sınıf) bağımlı olmaktadırlar. Bir başka açıdan bakarsak, üst seviyeli işlem yapan metodlar, alt seviyeli işlem yapan metodları kullanmaktadırlar. Haliyle alt seviye metodlarda olası her değişiklik üst seviye metodlarda değişikliğe sebep olması üst seviyenin alt seviyeye bağımlılığını göstermektedir. Haliyle DIP bize bu bağımlılığın ters çevrilmesini prensip edinmemizi önermektedir.

Aşağıda örnek bir bağımlılık senaryosu paylaşılmaktadır.

    class Imalat
    {
        //High Level Class
        public void Olustur()
        {
            Kek kek = new Kek();
            kek.KekYap(true);
        }
    }

    class Kek
    {
        //Low Level Class
        public void KekYap(bool Kakao)
        {
            //Process
        }
    }

Yukarıdaki “Imalat” sınıfı içerisindeki “Olustur” metodu, “Kek” sınıfı içerisindeki “KekYap” isimli metoda bağımlıdır. Bunun sebebi “KekYap”‘ın “Olustur” içerisinde kullanılmasıdır. İlgili metotda yapılacak tüm değişiklikler “Olustur” içerisinde de değişiklik gerektirecektir.

Bağımlılığı aşağıdaki diyagramdan da net bir şekilde görebilmekteyiz.
Bağımlılığın Ters Çevrilmesi Prensibi(Dependency Inversion Principle - DIP)

Nesne tabanlı yaklaşımlarda bu tarz bağımlılıklar soyutlama kullanılarak minimize edilebilmektedirler.

    interface IGida
    {
        void Yap(bool Kakao);
    }

    class Imalat
    {
        //High Level Class
        IGida gida;
        public Imalat()
        {
            gida = new Kek();
        }
        public void Olustur()
        {
            gida.Yap(true);
        }
    }

    class Kek : IGida
    {
        //Low Level Method
        public void Yap(bool Kakao)
        {
            //Process
        }
    }

Yaptığımız bu işlemi aşağıdaki diyagramda ele alalım.
Bağımlılığın Ters Çevrilmesi Prensibi(Dependency Inversion Principle - DIP)
Dikkat ederseniz yaptığımız işlem neticesinde alt seviye sınıfımızı Interface sayesinde soyutlaştırarak, üst seviye sınıfımızda alt seviye sınıfına dair olan bağımlılığı tersine çevirmiş bulunmaktayız. Yani gördüğünüz gibi alt seviye sınıfımız, Interface’e bağımlı bir hale gelmiştir. Ee ilgili Interface’de üst seviye sınıf tarafından refere edildiğinden dolaylı yoldan bağımlılık alt seviyeden üst seviyeye doğru olmuştur diyebiliriz.

Okuduğunuz için teşekkür ederim…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar dilerim…

Bunlar da hoşunuza gidebilir...

12 Cevaplar

  1. Kerim DEMİRER dedi ki:

    S.a Hocam. Bütün SOLİD prensiplerini okudum. Bunlardan önce de dependency injection konusu ile ilgilenmiştim. Şahsi görüşüm olarak diyorum ki . Her yol dependency injection’a çıkıyor. Temelde bu tasarım desenini anlayıp kavramak SOLİD’i büyük oranda kavramayı sağlar bence. Ve netice olarak SOLİD bize diyor ki.
    Herkes kendi işine baksın kardeşim. Üstünüze vazife olmayan işlere burnunuzu sokmayın sorun çıkmaz diyor.
    Classa sen git sadece kendi işini yap diyor. İnterface ‘a sen git kendi işine bak diyor. Open closed ile sana ne gelenden gidenden sen verilen işi yap diyor sadece. Bence hepsinin özeti dependency injection tasarım deseni. 🙂

  2. veysel dedi ki:

    Tebrik ederim cok harika izahat olmus

  3. Murad dedi ki:

    Merhaba, bunlar ne anlama geliyor aciklarmisiniz rica etsem:

    Üst seviyeli işlem yapan sınıflar(High Level Class – Yüksek Dereceli Sınıf)
    Alt seviyeli işlem yapan sınıflara(Low Level Class – Düşük Dereceli Sınıf)

    yani soyle soyleyim, “Üst/Alt seviyeli işlem yapan sınıflar” derken neyi kast ediyorsunuz? tesekkurler

    • Gençay dedi ki:

      Merhaba,

      Üst seviyeden kasıt operasyon sahası iken, alt seviyeden kastımız ise operasyonun ta kendisidir. Şöyle düşünebilirsiniz ki;
      “Banka” sınıfı üst seviye bir sınıfken, “EFTIslemleri” sınıfı ise alt seviye bir sınıftır ve “Banka” sınıfında yeri ve zamanı geldiğinde çağrılıp kullanılır. Dolayısıyla “Banka” sınıfı “EFTIslemleri” sınıfına bağımlıdır.

      Sevgiler.

  4. Tahir Yıldırım dedi ki:

    Hocam benim anlayamadığım bir husus var alt sınıfta değişiklik yapınca üst sınıfın etkilenmemesi ve üst sınıftaki değişikliğe alt sınıfın uyum sağlaması hususu rica etsem bunu açabilmeniz mümkün mü ?

    Sizin kodda böyle bir düzenleme yaptım DIP hakkında okuduklarımdan anladığım ile sizce doğru mudur ?

        interface IGida
        {
            void Yap(bool Kakao);
        }
    
        class Imalat
        {
            //High Level Class
            IGida _gida;
            public Imalat(IGida gida)
            {
                _gida = gida;
            }
            public void Olustur()
            {
                _gida.Yap(true);
            }
        }
    
        class Kek : IGida
        {
            //Low Level Method
            public void Yap(bool Kakao)
            {
                GidaYap(Kakao);
            }
    
            private void GidaYap(bool Kakao)
            {
                if (Kakao)
                {
                    Console.WriteLine("Kek yapıldı");
                }
                else
                {
                    Console.WriteLine("Kek yapılamadı");
                }
            }
        }
    
  5. Ugur Dundar dedi ki:

    Tersine çevirme doğru bir isimlendirme mi gerçekten.. Yani şimdi Alt Sınıf, Üst Sınıfa öı bağımlı oldu tam olarak.. Aklıma yatmadı 🙂

    • Gençay dedi ki:

      Problem nedir?

    • Çağatay Alparslan dedi ki:

      Şimdi de örneği şöyle düşün bakalım, Kakao ile kek, dondurma, muhallebi (yapabileceğini), başka bir oluş mekanizması içeren sade kakaolu sıcak içecek, kakaolu süt, kaka likörü (hazırlayabileceğin) dikkat et parantez içlerinde iki farklı hareket var ve her hareketin ilgi alanında birden fazla tip var; Şimdi de Alt Sınıf-Üst Sınıf ilişkisi var mı? Yeni bir instance oluşturmadan bunlardan kaç tane üretebilirsin?
      Aslına bakarsan Gençay beyin örneğinde bile bahsettiğin bir bağımlılık yok, öyleymiş gibi hissediliyor… Dependency Inversion prensibindeki tek bağımlılık Container ‘dır ve performans açısından çok can sıkar… Endişen beyhude yani !

  1. 09 Mart 2018

    […] Injection(Bağımlılık Enjeksiyonu) Aslında bir tasarım deseni olan ve hatta Dependency Inversion ile prensip haline(SOLİD) gelen Depedency Injection, programatik olarak bağımlılıkları […]

  2. 24 Eylül 2022
  3. 22 Eylül 2023

Kerim DEMİRER için bir yanıt yazın Yanıtı iptal et

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir