Open Closed (OCP) Prensibi

open closed prensibi

Bu makalede SOLID prensiplerinin ikinci ayağı olan ve Robert C. Martin’in en önemli prensip olarak kabul ettiği Open Closed prensibi ele alınacaktır. Bir önceki makalede Single Reponsibility Prensibini incelemiştik.

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. (Yazılımlar gelişime açık, değişime kapalı olmalıdır.)

Robert C. Martin

Bir yazılım projesinin geliştirilme ve destek süreçlerinde müşterilerden iteratif şekilde revizyon talepleri gelmektedir, başta istenen ile sonda istenen çoğunlukla aynı olmayacaktır. İşte tam bu noktada yapılacak değişikliklerin sisteme kolaylıkla ve sorunsuz şekilde bütünlük sağlaması ve sorun çıkartmaması için bu prensibi kullanmalıyız. Açıklamadan sonra bu prensip; yazılımı oluşturan her bir parçanın (sınıf, modül, fonksiyon v.b.) geliştirmelere açık, değişime kapalı olmasını ifade eder.

Bu prensibi uygulamanın en basit yolu mevcut işlevselliği koruyarak, yeni eklenecek işlevlerin türetilmiş (derived) sınıflar aracılığıyla sağlanması olacaktır. Bu prensip uygulanmadığında farklı işlevler tek merkezden yürütülmeye çalışılacağından Single Responsibility Prensibi de çiğnenmiş olacaktır.

Konuyu bir örnekle pekiştirelim. Senaryoya göre bizden bir kargonun gönderim ücretinin ağırlığına ve taşıma durumuna göre hesaplanması istenmektedir. Buna göre konu üzerine hiç düşünmeden aşağıdaki kodu yazdığımızı düşünelim.

public class Shipment
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ShipmentType { get; set; }
    public double Weight { get; set; }
    public decimal CalculateCost()
    {
        if (ShipmentType == "Overland")
            return Weight * 1.5;
        else if (ShipmentType == "Oversea")
            return Weight * 2.0;
        else if (ShipmentType == "Overair")
            return Weight * 2.5;
        else return Weight;
    }
}

Şu anda karayolu, denizyolu ve havayolu ile taşıma yapmaktayız, müşterimiz yarın demiryolu ile de taşımaya başlayınca kodumuzu -prensibi çiğneyerek- değiştirmemiz gerekecek ve if-else merdivenine yeni basamak eklememiz gerekecek. Şimdi yazdığımız bu kodu refoctor ederelim.

İlk olarak sınıfımızı soyutlayarak, tip alanını kaldıralım.

public abstract class Shipment
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Weight { get; set; }

    public abstract decimal CalculateCost();
}

Daha sonra tip alanlarını geliştirme olarak ele alalım.

public class OverlandShipment : Shipment
{
    public override decimal CalculateCost()
    {
        return Weight * 1.5;
    }
}

public class OverseaShipment : Shipment
{
    public override decimal CalculateCost()
    {
        return Weight * 2.0;
    }
}

public class OverairShipment : Shipment
{
    public override decimal CalculateCost()
    {
        return Weight * 2.5;
    }
}

Kodumuzu refactor ederek değişime kapalı, geliştirmeye açık hale getirdik. Nasıl uygulayacağımızı da ele alıp makaleyi sonlandıralım.

static void Main(string [] args)
{
	var shipments = new List<Shipment>
	{
		new OverlandShipment { Id = 1, Name = "Kargo #1", Weight = 5.2 },
		new OverseaShipment { Id = 2, Name = "Kargo #2", Weight = 3.4 },
		new OverairShipment { Id = 3, Name = "Kargo #3", Weight = 2.6 }
	};
	
	foreach(var shipment in shipments)
	{
		Console.WriteLine($"Shipment cost for {shipment.Name} is {shipment.CalculateCost()}");
	}
}

Görüldüğü üzere kodumuz artık gelişime açık, değişime kapalı hale gelmiştir.

You may also like...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir