Refactoring işlemi kodun işlevini değiştirilmeden daha okunabilir hale getirmek amacıyla yeniden düzenlenmesi işlemidir. Özellikler test güdümlü programlamada (Test Driven Development) gerekli olan gevşek bağlılık (loosely coupled) prensibinin uygulanabilmesi için bazı kurallara uymak durumunda kalabiliyoruz.
Özellikle sıkı bağlılığın(tightly coupled) yok edilmesi için uygulamak gereken bazı özellikler vardır. Bunlar:
- Uygulama kodunu bir interface ile temsil etmek
- Test edilen sınıfa soyut nesneleri aktararak soyut nesneler üzerinden işlemleri yapmak.
- Soyut Interface nesnesini constructor seviyesine almak.
- Soyut interface nesnesini bir property olarak almak.
- Soyut interface nesnesini metod çağırma işleminden önce almak.
Constructor seviysinde nesne almak (Constructor Injection)
Bu senaryoda, constructor yardımıyla interface nesnesini kabul edeceğiz. Daha sonra alınan bu nesne kullanılmak üzere private erişim belirleyicili bir metoda aktarılır.
public class ReportSender{
private IReporter reporter;
public ReportSender(IReporter reporter){
this.reporter = reporter;
}
// Diğer üyeler
//....
//..
//.
}
Problemler
Test edilen sınıf eğer birden fazla soyut nesne alıyorsa constructor sayısı veya bir constructorun aldığı parametre sayısı artacak. Bu da kodun düzenini ve okunabilirliğini bozacaktır.
Bu sorunu çözmek için kullanılacak yöntemlerden biri, gerekli tüm başlangıç değerlerinin bir sınıf içerisinde başlatılmasıdır (parameter object refactoring).
Bir diğer çözüm ise bağımlılıkların ters çevrilmesidir(Inversion of Controls IoC). Bu işlemi yapan hazır paketler bulunmaktadır. Örneğin Spring.NET, Castle Windsor, Ninject gibi. Bu konteynır yapılar sayesinde bir interface nesnesine karşılık gelecek somut nesne belirlenir ve o interface görüldüğünde somut nesnesi bağlanmaktadır.
Ne zaman kullanılmalı
Constructor seviyesinde nesneler alıp başlatmak istediğinizde, IoC konteynırlar nesne oluşturma sırasında hız kazandırmaktadır. Öte yandan constructor parametreler, API’nizi kullananlara, parametrenin opsiyonel olmadığını göstermektedir.
Property seviyesinde nesne almak(Property Injection)
Bu senaryoda, esnek bağı sağlayacak olan, bir property olacaktır. Dependency injection olarakta bilinen bu teknik bir önceki yönteme benzemektedir. Constructor injection gibi bu yöntem de API üzerinde gerekli bağımlılıkları göstermektedir.
public class ReportSender{
public IReporter Reporter {get; set;};
// Diğer üyeler
//....
//..
//.
}
Ne zaman kullanılmalıdır
Bu teknik, bağımlılığın isteğe bağlı olduğu durumlarda kullanılır. Bağlılığın opsiyonel bırakılmak istenen durumlarda tercih edilebilir.
Metod çığırılmadan önce nesne almak
Bu teknikte ise nesneyi almak için property veya constructor yerine factory sınıfları kullanılır. Bu sayede soyut nesne, sınıf içerisine aktarılmış olur.
public class ReportSender{
private IReporter reporter;
public ReportSender(IReporter reporter){
this.reporter = FactoryClass.CreateReportInstence();
}
// Diğer üyeler
//....
//..
//.
}
Ne zaman kullanılmalıdır
Bu teknik, sınıf girdilerini(input) kontrol etmek istendiğinde kullanılabilir. Ancak test ortamında, bağımlılıkları test edmek istediğinizde kötü sonuç verecektir. Çünkü test ortamında sınıf içine mock object aktarıp davranışları test etmek istendiğinde başarısız oluruz.