Refactoring Nedir? - Bölüm 2

Önceki yazıdaRefactoring nedir?” konusuna kısa bir açıklama ile başlangıç yapıp devamında örnekler ile konuyu anlamaya çalıştık. Örnek bir kod parçasını refactor ederek belirli bir aşamaya kadar ilerledik. Bu yazıda düzenlediğimiz kodların son hali üzerinden, refactoring işlemine devam edeceğim.

Önceki yazıda refactor ettiğimiz Movie.cs sınıfının son hali aşağıdaki gibi olmuştu.

Movie.cs

Bu kodlarda bir sorun var. Sınıf içerisinde Movie.cs sınıfının tipleri integer değerler ile temsil ediliyor ve bu değerlere göre filmin fiyatı hesaplanıyor. Böyle bir tasarım sürekli if-else veya switch-case bloklarına sebep oluyor. Bu örnekte eğer yeni bir film tipi gelirse, tipe göre işlem yapılan her kod bloğun da değişiklik yapmak gerekecek.

State Pattern

Bu sorunu Movie.cs sınıfından türeyen alt sınıflar ile çözebilirdik. Böylece her sınıf kendi içinde, kendine ait hesaplamaları (fiyat hesaplaması) yapabilirdi ama bu örnekte böyle bir çözüm işe yaramaz. Çünkü filmin tipi zaman içerisinde değişebilir. İlk başta New Release tipinde olan bir filmin tipi bir süre sonra değişir ve fiyat hesaplaması da değişmek zorunda kalır. Bir nesne kendi yaşam döngüsü içerisinde kendi sınıfının tipini değiştiremez.

Bu sorunun çözümü için State Pattern tasarım desenini kullanabiliriz. Yeni tasarım aşağıdaki gibi olacaktır.

Applied State Pattern to Movie.cs

Bu şekilde bir tasarım yapılınca, nerede ihtiyacımız olursa orada yeniden fiyat hesaplaması yapabiliriz.

Önceki makalede de bahsetmiştik, değişiklikleri sırası ile ve küçük adımlarla yapacağız. State tasarım desenini uygulamak için 3 aşama ile kodları değiştireceğim. Bu aşamalar Replace Type Code with State/Strategy, Move Method, Replace Conditional with Polymorphism.

İlk Aşama : Replace Type Code with State/Strategy

Yeni sınıfları ekliyorum.

Price.cs and subclasses

Yeni sınıflara göre PriceCode değişkeninin getter ve setter ‘larını değiştiriyorum.

Movie.cs

İkinci Aşama : Move Method

GetCharged metodunu Price.cs sınıfı içine taşıyorum.

Move Method - Movie.cs to Price.cs

Son Aşama : Replace Conditional with Polymorphism

Artık switch-case bloklarından kurtulabiliriz. Bunun için her case bloğunu ilgili alt sınıfa metot olarak taşıyorum. Aynı aşamaları GetFrequentRenterPoints metodu için de uyguluyorum. Kodların son hali aşağıdaki gibi oluyor.

Replace Conditional with Polymorphism

Gördüğünüz gibi PriceCode değişkeninden, integer olarak tanımlanan film tipinden ve switch-case bloklarından tamamen kurtulduk. Bu arada GetFrequentRenterPoints metodunu taşırken GetCharged ‘dan farklı olarak, abstract tanımlamadık. Bunun yerine virtual tanımladık ve sadece, NewReleasePrice içinde override ettik. Böylece diğer alt sınıflar, varsayılan olarak, üst sınıfın hesaplamasını kullanacak.

Aşamalı ve küçük adımlarla ilerleyince refactoring daha da basitleşiyor. Her aşamada ihtiyaçları ve gereksiz kodları daha net görebiliyorsunuz. Hem de her küçük değişiklikten sonra kodların takip edilmesi ve test edilmesi daha kolay oluyor. Böylece yapılan değişikliklerin, sistemin başka yerlerini etkileme riskini de düşürmüş oluyorsunuz.

İlk makalenin başında paylaştığım kodların tamamının refactor edilmiş son hali ise aşağıdadır.

Kodların son halinin akış ve class diagram’ı

Flow Diagram
Class Diagram