SOLID prensiplerinin “O”su Open-Closed Prensibi yani Açık-Kapalı prensibi bir sınıfın veya modülün geliştirme için açık ancak değiştirme için kapalı olması gerektiğini söyler.
Peki bu ne anlama geliyor?
Daha basit kelimelerle ifade etmek gerekirse bu prensip yazılımcıları var olan kodu güncellemeden yeni özellikler ve fonksiyonlar eklemeye imkan sağlayacak bir tasarım kullanmaya teşvik ediyor.
Geliştirmeye açık bir kod yapısı kurarak yeni gelen istekler için var olan kodları sürekli değiştirmektense yeni kodlar eklemeyerek bakımı daha kolay ve daha esnek yapılar kurmayı amaçlıyor.
Gelişime açık olmak ne anlama geliyor?
Kısaca bir sınıfı veya modülü mevcut olan işlevselliğini değiştirmeden genişletebilmelisiniz. Yeni bir özelliğin eklenme süreci halihazırda çalışan modülleri ve kodları etkilememeli.
Değişime kapalı olmak ne anlama geliyor?
Bir sistem üzerinde halihazırda tamamlanmış ve test edilmiş modüllerin, sınıfların kodlarında bir değişiklik yapılmamalı, çünkü sonradan yapılan kod değişiklikleri çalışan sistemlerde sorunlar yaşanmasına sebep olabilir. Bunun yerine yeni özellikler eklemek için yeni sınıflar ve modüller oluşturarak var olan kodu geliştirip genişletebilirsiniz.
Peki bu prensip koda nasıl uygulanır bir de ona bakalım.
Öncelikle Open-Closed prensibine uygun olmayan bir örnekle başlayalım. Kahve yapmak için kullandığımız bir CoffeeMachine sınıfımızın olduğunu düşünelim, bu sınıfımızın içerisinde de filtre kahve yapmak için MakeFilterCoffee isimli bir metodumuzun olduğunu düşünelim.
public class CoffeeMachine
{
public void MakeFilterCoffee()
{
Console.WriteLine("Filtre Kahve yapılıyor...");
}
}
Biz var olan CoffeeMachine sınıfımıza Amerikano ve Latte yapma özelliklerini eklemek istiyoruz, bunu basitçe bu metotları CoffeMachine sınıfına ekleyerek yapabiliriz. Ancak bu CoffeeMachine sınıfında değişiklik yaptığımız anlamına gelir ve bu Open-Closed prensibine aykırı bir durum oluşturur.
public class CoffeeMachine
{
public void PrepareFilterCoffee()
{
Console.WriteLine("Filtre Kahve yapılıyor...");
}
public void PrepareAmericano()
{
Console.WriteLine("Amerikano yapılıyor...");
}
public void PrepareLatte()
{
Console.WriteLine("Latte yapılıyor...");
}
}
Bu şekilde gördüğünüz gibi istediğimiz özellikleri ekledik ancak sınıf üzerinde bir değişiklik yaptık ve bu Open-Closed prensibini çiğnediğimizi gösteriyor.
Peki bunu nasıl doğru şekilde yapabilirdik?
// Önce, temel görev olan kahve hazırlama işlevselliğini soyut şekilde temsil eden bir interface oluşturalım.
public interface IPrepareCoffee
{
void Prepare();
}
// Daha sonra bu arayüzü kullanan ve kahve hazırlama işlevini içeren sınıflar oluşturalım.
// Filtre kahve sınıfı
public class FilterCoffee : IPrepareCoffee
{
public void Prepare()
{
Console.WriteLine("Filtre kahve yapılıyor...");
}
}
// Amerikano sınıfı
public class Americano : IPrepareCoffee
{
public void Prepare()
{
Console.WriteLine("Amerikano yapılıyor...");
}
}
// Latte Sınıfı
public class Latte : IPrepareCoffee
{
public void Prepare()
{
Console.WriteLine("Latte yapılıyor...");
}
}
// Son olarak da bu sınıfları kullanarak istediğimiz kahveyi hazırlayacak sınıfı oluşturabiliriz.
public class CoffeeMachine
{
public void PrepareCoffee(IPrepareCoffee coffee)
{
coffee.Prepare();
}
}
Eğer tasarımı bu şekilde yaparsak yeni kahve çeşitleri eklendiğinde var olan sınıflarda güncelleme yapmamıza gerek olmadan özelliği ekleyebiliriz. Bu da Open-Closed prensibine uygun olarak kodun geliştirilebilir, genişletilebilir olmasını sağlar.
Örneğin:
CoffeeMachine machine = new CoffeeMachine();
machine.PrepareCoffee(new FilterCoffee()); // Filtre kahve yapılıyor...
machine.PrepareCoffee(new Americano()); // Amerikano yapılıyor...
machine.PrepareCoffee(new Latte()); // Latte yapılıyor...
Bu şekilde yeni kahve türleri eklense bile var olan kodları değiştirmeden kodu geliştirebiliriz.
Önceki yazılar:
Solid Prensipleri
Single Responsibility Prensibi
Sonraki yazılar:
Liskov Substitution Prensibi
Interface Segregation Prensibi
Dependency Inversion Prensibi