Published on

Open-Closed Prensibi Nedir ?

Authors
  • avatar
    Name
    Alperen Önal
    Twitter

Yazılım varlıkları (sınıflar, modüller, işlevler, vb.) genişletmeye açık ancak değişiklik için kapalı olmalıdır.(Robert Cecil Martin, 2007).

Bob amcamızın da dediği gibi Open-Closed prensibinde bir sınıfı, modülü, işlevi vs. genişlemeye açık ancak değişiklik için kapalı şekilde tasarlamalıyız.

Genişlemeye Açık

Mevcut olan yazılım varlıklarını değiştirmeden, bir yazılım varlığına bir davranış ekleyebilmeli veya genişletebilmeliyiz.

Değişikliliğe Kapalı

Bir yazılım varlığına yeni bir davranış ekleneceği zaman, mevcut olan yazılım varlıklarının değiştirilmemesi gerekmektedir.

Amaç :

  • Kodda değişiklik yapmadan yeni davranışlar/özellikler ekleme.
  • Mevcut işlevselliğin bozulmasını engelleme.

Örneğin aşağıdaki gibi bir kodumuz olsun :


class OyuncuCombat
{
    int verilenHasarMiktari;

    public void HasarVer(CanavarA hedef)
    {

        hedef.HasarAl(verilenHasarMiktari);

        //diğer işlemler


    }

    //diğer işlemler
}

class CanavarA
{
    int maxCan;

    public void HasarAl(int alinanHasar)
    {
        maxCan = maxCan - alinanHasar;

        //diğer işlemler

    }
    //diğer işlemler
}

Bu kod, bu haliyle SOLID prensiplerini ihlal etmiyor gibi gözükebilir. Ancak bu ihlali ekleme yapınca göreceğiz :)




Oyunumuza yeni bir karakter eklemek istedik ve dolayısıyla ekleyeceğimiz yeni karaktere de zarar verebiliriz bu yüzden kodu tekrardan düzenleyelim.

Aşağıdaki gibi bir düzenleme ile bu sorunun üstesinden gelebiliriz. Ancak farkettiğimiz üzere Open-Closed prensibi ihlal edildi.

Oyuncunun, yeni eklenen bir karaktere saldırabilmesi için OyuncuCombat sınıfını tekrardan düzenlemek zorunda kaldık.

Peki ya, 50 farklı canavar 10 farklı karakter eklemek isteseydim ? -Evet, her biri için tek tek OyuncuCombat sınıfına if döngüleri eklemek zorunda kalacaktım.

Bu saçma yapı ile durduk alakasız bir bağımlılık yaptık ve başımıza iş açtık.


class OyuncuCombat
{
    int verilenHasarMiktari;

    public void HasarVer(object hedef)
    {

        if (hedef is CanavarA)
        {
            CanavarA canavar = (CanavarA)hedef;
            canavar.HasarAl(verilenHasarMiktari);
        }


        if (hedef is KarakterA)
        {
            KarakterA karakter = (KarakterA)hedef;
            karakter.HasarAl(verilenHasarMiktari);
        }

        //diğer işlemler


    }

    //diğer işlemler
}

class CanavarA
{
    int maxCan;

    public void HasarAl(int alinanHasar)
    {
        maxCan = maxCan - alinanHasar;

        //diğer işlemler

    }
    //diğer işlemler
}


class KarakterA
{
    int maxCan;

    public void HasarAl(int alinanHasar)
    {
        maxCan = maxCan - alinanHasar;

        //diğer işlemler

    }
    //diğer işlemler
}




Eğer yeni bir karakter eklemek istiyorsam bu karakteri alakadar eden her şey yalnızca bu karakteri alakadar eder. Yani, yeni bir karakter yahut canavar eklemek için OyuncuCombat sınıfını bozmamalıyız.

Bu yüzden interface'lere başvurabiliriz.

Aşağıdaki örnekle OyuncuCombat sınıfını Open-Closed prensibine uygun hale getirdik.

  • OyuncuCombat sınıfında değişiklik yapmadan yeni davranışlar/özellikler ekleyebiliriz.(✓)


class OyuncuCombat
{
    int verilenHasarMiktari;

    public void HasarVer(ICanli hedef)
    {
        hedef.hasarAl(verilenHasarMiktari);


        //diğer işlemler


    }

    //diğer işlemler
}

interface ICanli
{
    public void HasarAl(int alinanHasar);



}

class CanavarA : ICanli
{
    int maxCan;

    public void HasarAl(int alinanHasar)
    {
        maxCan = maxCan - alinanHasar;

        //diğer işlemler

    }
    //diğer işlemler
}


class KarakterA : ICanli
{
    int maxCan;

    public void HasarAl(int alinanHasar)
    {
        maxCan = maxCan - alinanHasar;

        //diğer işlemler

    }
    //diğer işlemler
}





Okuduğunuz için teşekkürler bir serinin kalanına devam etmeyi unutmayın :) Liskov Substitution Prensibi Nedir ?