Teknik Konular - Dependency Injection 1 - ihan3t

ihan3t

Kadim Üye
7 Şub 2012
5,018
22
Merhaba tht üyeleri, hayırlı akşamlar.

Canım sıkıldı, biraz yazılım tasarımsal konu olan dependency injection konusuna değineceğim.

Birçoğumuz kod yazıyoruz, peki bu kodları olması gerektiği gibi mi yazıyoruz?
Yeterince iyi tasarlıyor muyuz?
Object oriented standartlarına uyuyor muyuz?

Solid prensiplerini uyguluyor muyuz?

Bir saniye, Solid mi, o da ne ki?

Solid, object orientedın etkili kullanılması adına Robert C. Martin tarafından ortaya atılan prensipler bütünüdür.

S - Single-responsiblity principle
O - Open-closed principle
L - Liskov substitution principle
I - Interface segregation principle
D - Dependency Injection/Inversion principle

konularının baş harflerinden oluşur.

Bunların her biri ayrı ayrı ele alınması anlatılması gereken konular. Bir yazı dizisi halinde bunları anlatmayı düşünüyorum ve başlangıç olarakta en sonuncuyu seçtim.

Solid prensiplerini uygulamadan ne kadar doğru tasarlanmış object oriented kod yazıyoruz bunu bir sorgulamak gerekli.

Dependency injection için en mükemmel anlatım olarak öncelikle şunu bir not düşelim :

"Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions."

Yani meali diyor ki "classlarımız birbirine bağımlı olmamalı, soyutlamalara bağımlı olmalı".

Şimdi bu pratikte ne anlam ifade ediyor bir örnekle inceleyelim.

Farz edelim ki mail gönderme işlemi yapan bir uygulamamız var.

Uygulamamızda üye olunduğunda mail gönderiliyor olsun. Hadi bunu pseudo code olarak gösterelim:

Kod:
class UserService(){
    private GmailService mailService;

    public UserService(){
        mailService = new GmailService();
    }

    public SignUp(string isim, mail){
        //burada üye olma işlemlerini yaptık

        mailService.SetReceiver(mail)
                         .SendMail("Hoşgeldin yeni üye");
    }

}

public static class Main(){
    UserService userService = new UserService();
    userService.SignUp("ihan3t","[email protected]");
}

Buradaki kod gayet güzel çalışıyor. UserService sınıfı ile kullanıcı işlemlerini yapıyoruz, GmailService sınıfı ile gmaile hoşgeldin üye maili gönderiyoruz.

Peki burada sorun ne?

- Buradaki sorun UserService sınıfı GmailService sınıfına "tightly coupled" yani sıkı sıkıya bağımlı/bağlanmış.

- GmailService sınıfında yapılabilecek herhangi bir değişiklik direkt olarak UserService sınıfını etkileyecek.

- Yarın öbür gün YandexService isminde bir classımız olsa, kodumuza müdahale edip değişiklik yapmamız gerekecek.

Oysa ki SOLID bize bunu yapmamamız gerektiğini söylüyor. (open closed principle, bunu başka bir konuda anlatacağım)

Solid bize diyor ki, kodun geliştirmeye açık - düzenlemeye kapalı olsun.

Dependency injection bize diyor ki, classlar classlara değil, abstraction lara bağımlı olsun.

Peki bunu nasıl uygularız?

Şimdi bu işlemi yapan kodumuzu dependency injection ile baştan yazalım.

Kod:
interface IMailService(){
    IMailService SetReceiver(String isim);
    **** SendMail(String content);
}

class GmailService implements IMailService(){
    public IMailService SetReceiver(String isim){
        //işlemler
    }

    public **** SendMail(String content){
        //işlemler
    }
}

class UserService(){
    private IMailService mailService;

    public UserService(IMailService _mailService){
        mailService = _mailService;
    }

    public SignUp(String isim, String  mail){
        //burada üye olma işlemlerini yaptık

        mailService.SetReceiver(mail)
                         .SendMail("Hoşgeldin yeni üye");
    }

}

public static class Main(){
    IMailService mailService = new GmailService();
    UserService userService = new UserService(mailService);
    userService.SignUp("ihan3t","[email protected]");
}

Kodumuzu bu hale getirdik.

Peki neler değişti?

Bir adet IMailService adında soyutlamayı sağlan interface imiz var.
Bunu implement eden bir concrete sınıf olan GmailService imiz var.
Soyutlamaya bağlı olan bir UserService sınıfımız var.

Artık UserService hangi mail servisi yoluyla işlem yaptığını bilmiyor, sadece ne işlem yapacağını biliyor. Zaten olması gereken de budur. Kimin neyi nasıl yaptığını bilmesi gerekmiyor, yapacağı işlemi bilmesi yeterli, bu işlemi yapan concrete sınıflar dışardan inject edilmeli.

Main sınıfımızda ise IMailService tipinde bir GmailService oluşturduk ve bunu constructor yoluyla UserService sınıfıne inject ettik.

İhtiyacımız olduğu zaman HotmailService gibi bir sınıfı IMailService i implement edip oluşturabilir ve sadece UserService in constructor ına parametre olarak vererek uygulamamızın işleyişini değiştirebiliriz.

Hatta elimizde birden fazla mailer sınıfı varsa, bunu seçimlere bağlı hale getirerek, uygulamanın çalışma zamanında değiştirme imkanımız olabilir. Bunu da Factory Design Pattern ile sağlayabiliriz. Bu da başka bir yazımın konusu olsun.

C# tarafında dependency injection için autofac, ninject, windsor gibi IoC container lar mevcut. Bu containerlar sizin yerinize injcetion işlemini yapıyor. Siz container a hangi tip için hangi concrete leri inject edeceğinizi belirtiyorsunuz..

Daha derin detaylı araştırma yapmak için sizlere birçok keyword ve bir başlangıç noktası edinebileceğiniz örnekler verdim. Buradan ileriye gitmek sizin kendi araştırmanız ile olacaktır.

Herkese iyi çalışmalar, ihan3t.
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.