C#’ta bir sınıf (class) başvurulan (referenced) bir tip olarak kabul edilir. Sınıflar içinde properties, methods, constructors ve programlama dilinde mevcut olan diğer bileşenler oluşturulabilir. Bir sınıf içinde birden fazla metot tanımlayabiliriz, ancak C#’ta bir metodun içinde concrete yani somut bir sınıf oluşturulamaz. Bu nedenle sınıflar metotlardan bir seviye daha üsttedir ve temiz kod yazımında son derece önemlidir.
İstediğimiz kadar metot ekleyebiliriz ama metodun içinde yeni bir sınıf tanımlayamayız. Normal koşullarda sadece nested class (iç içe sınıflar) sınıf içinde tanımlanabilir ama metodun içinde somut bir class tanımlamak mümkün değildir.
Doğru tasarlanmış sınıflar, okunabilirliği artırır, bakımı kolaylaştırır ve projenin uzun vadede sürdürülebilir olmasını sağlar. Bu nedenle sınıf tasarımında belli kurallara uymak büyük faydalar sağlar. C# sınıfları tasarlanırken dikkat edilmesi gereken temel kuralları şöyle özetleyeyim
Class içi düzen
Bir sınıfın içinde tanımlanan elemanların belli bir sıralamayla düzenlenmesi tavsiye edilir. Genel olarak şu sıra önerilir:
- Sabit değişkenler (constants)
- Alanlar (variables/fields)
- Özellikler (properties)
- Yapıcı (constructor)
- Metotlar (methods)
- Public, protected, private methods
Resmi olarak bu sıralamaya dair bir kural bulunmuyor. Hepsi de kullanılmak zorunda değil. İhtiyaçlarınız doğrultusunda hareket edin.
Class içi tutarlılık (consistency)
Sınıfların iç organizasyonunda kullanılan bu düzen, yalnızca tek bir projede değil, bir organizasyondaki tüm projelerde uygulanmalıdır. Bir şirketteki tüm sınıf kullanımları tüm projelerde benzer olduğunda anlaması daha kolay olur. Çünkü standartlar belirlenmiştir.
Class size
Sınıflar mümkün olduğunca küçük olmalıdır. Ancak bir class büyüklüğünü sadece satır sayısı belirlemez. Daha önemli olan, sınıfın üstlendiği sorumlulukların sayısıdır. Yani her işi tek sınıfa yaptırırsanız o alan şişer ve karmaşık hale gelir. Dolayısıyla altını çizelim, her işi bölün ve sınıflara ayırın.
Single responsibility
Her class yalnızca tek bir iş yapmalıdır. Birden fazla iş üstlenen sınıflar genellikle ilerleyen aşamalarda bakım ve genişletme açısından sorun çıkarır.
Örneğin “DataManager” adında bir sınıf oluşturdunuz. İçinde hem ürün getirme hem de müşteri bilgilerini getirme işlemlerinin yapıldığını düşünün. Niye ürün için ayrı kullanıcı için ayrı bir sınıf oluşturmuyorsunuz? Sizi ayrı sınıflar oluşturmaktan kaçıran şey nedir? İyi düşünmek gerek. ProductRepository ve CustomerRepository ayrı oluşturursanız neyin nerede olduğu daha belirli olur.
Bu kadarla bitiyor mu? Son bir prensip daha var.
Sınıfları anlamlı isimlendirme
Sınıflara verilen isim sorumluluğunu açık bir şekilde ifade etmelidir. Belirsiz veya aşırı genel isimler, sınıfın fazla sorumluluk üstlendiğinin işaretidir. Örneğin “AbcHelper”, “AbcManager” gibi isimler genellikle belirsizdir. Çok genel isimlendirme olur. Bunun yerine “AbcCalculator” veya “AbcValidator” yazıldığında neye hizmet ettiğini de anlamış oluruz.
Dependency Inversion Principle (DIP) nedir?
Dependency Inversion Principle (DIP), SOLID prensiplerinden biridir ve şunu söyler: Yüksek seviyeli sınıflar (high-level modules), düşük seviyeli sınıflara (low-level modules) doğrudan bağımlı olmamalıdır. Hem yüksek seviyeli hem düşük seviyeli sınıflar, soyutlamalara (abstractions) bağımlı olmalıdır. Abstraction sınıflar ayrıntılara değil, ayrıntılar soyutlamalara bağlı olmalıdır. Bu neden önemli? Bu prensip ile birlikte sıınflar esnek, test edilebilir ve değişikliklere karşı dayanıklı olur.
Şöyle bir örnek verelim. Aşağıdaki örnekte bir abstract class veya bir interface kullanılmadan bir sınıf içerisinde direkt metot kullanılmış. Dolayısıyla sınıf direkt türetilebilir ve public olan metotları kullanabilirsiniz.
public class OrderService
{
private FileLogger _logger = new FileLogger();
public void PlaceOrder(string order)
{
_logger.Log("Order placed: " + order);
}
}
Bu sınıfın düzen içinde kalmasını sağlamak için bir abstract sınıfa bağlıyoruz.
public interface ILogger
{
void Log(string message);
}
public class FileLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine("File log: " + message);
}
}
ILogger kullanılacak metotları tanımlar. Bu interface’e bağlı olan sınıflar ise ondaki metotları kendisine entegre eder. Dolayısıyla ILogger üzerinden türetilen sınıflar sadece onda tanımlı olan metotları çalıştırabilir. Dışarıdan müdahale edilemez.
Sınıf içi düzen, tutarlılık, küçük boyut, tek sorumluluk ve anlamlı isimlendirme gibi kurallar uygulandığında ortaya çıkan kod, hem ekip çalışmasına hem de uzun vadeli projelere büyük katkı sağlar.
Reklam değildir: Düzenli bir proje oluşturmak, modern uygulamalar geliştirmek için önerim abp.io framework kullanımıdır. İhtiyacınız olan örnekler, best practice dökümanları hazır gösteriliyor. Mutlaka deneyin.
Yorum bırakın