📈
SOLİD
  • SOLİD PRINCIPLES
Powered by GitBook
On this page
  • Single-responsibility principle ;
  • Open-closed principle;
  • Liskov substitution principle;
  • Interface segregation principle;
  • Dipendencey Inversion Prensbles
  • Dependency Injection;

Was this helpful?

SOLİD PRINCIPLES

Last updated 4 years ago

Was this helpful?

//How to produce Clean Code? 
Bu sorunun cevabı ; 2000'li yılların başlarında 
                    SOLİD PRINCIPLES olarak yazılım camiasına sunulmuştur.

SOLID yazılım prensipleri; geliştirilen yazılımın esnek, yeniden kullanılabilir, sürdürülebilir ve anlaşılır olmasını sağlayan, kod tekrarını önleyen ve 2000'li yılların başında Robert C. Martin tarafından öne sürülen prensipler bütünüdür

  • Geliştirdiğimiz yazılımın gelecekte gereksinimlere kolayca adapte olması,

  • Yeni özellikleri kodda bir değişikliğe gerek kalmadan kolayca ekleyebileceğimiz

  • Yeni gereksinimlere karşın kodun üzerinde en az değişimi sağlaması,

  • Kod üzerinde sürekli düzeltme hatta yeniden yazma gibi sorunların yol açtığı zaman kaybını da minimuma indirmektir.

  • S— Single-responsibility "Her sınıfın veya metodun tek bir sorumluluğu olmalı "

  • O — Open-closed principle "Sınıflar değişikliğe kapalı ancak gelişime açık olmalıdır"

  • L — Liskov substitution principle "Liskov prensibi "

  • I — Interface segregation principle " Ara yüzlerin ayrılması prensibi"

  • D — Dependency Inversion Principle " Katmanlı mimarilerde üst seviye modüller alt seviyedeki modüllere doğruda bağımlı olmamalıdır "

Karşılaştığımız sorunları çözerken aklımızdan çıkarmamamız gereken ve programcılıkta hayat felsefi haline getirmemiz gereken şey şudur; nası ki Friedrich Nietzsche hayatının her anında üst insana (ubermensch) ulaşmaya çalışıyorsa bizde programcılığımızın her anında en temiz ve en bağımsız koda ulaşmalıyız. Bu şekilde yazdığımızın kodun devamlılığı sağlanabilir. İşte SOLİD prenciplerinin tam olarak ulaşmaya çalıştığı nokta budur.

Single-responsibility principle ;

Bu ilke "bir sınıfın değişmesi için yalnız bir nedeninin olması gerektiğini savunur" yani bir sınıfın az ve öz sorumluluğu olmalı karmaşık yapılardan her zaman kaçınılmalıdır. Bir class oluşturulurken sürekli " bu sorumluluğu buraya vermeli miyim ?" sorusu sorulmalıdır. Böylece kodlarda sonradan yapılacak bakım veya değişikliklerin maliyeti azalacaktır. Burada maliyetten kasıt iş yükü ve zamandır. Uygulamanızda katmanlı mimari kullanarak ve ata sınıflarınızda daha küçük sınıflara veye modüllere yani iş parçacıklarına ayırmanız gerekmektedir.

Open-closed principle;

Varlıklar(Entities) genişlemeye açık olmalı ancak değişikliğe kapalı olmalıdır. Zaten OOP genişlemeyi prensip edinilerek desteklenmiştir. Lakin bu değişikm esnasında yaratılan sınıflarda modifikasyona gerek kalmayacak şekilde mimariyi kurmamız gerekir. Bir sınıfın davraşınını değiştirmeden geliştirmemiz gerekir.

Bizden sınıflara yeni bir yetenek kazandırılmamız istenildiğinde, ilgili özellik için gövdesiz bir method yazılır ve tüm varlıklarda bu method implement edilir. Ve iplement edildiği yerde iş yüklenir. en masrafsız şekilde değişikliği yapmış olduk. Eğer ilerleyen süreçte yeni bir varlık eklenmek istenirse yine var olan yetenekler implemente edilerek kazandırılır. Ve böylece var olan classlarımızda herhangir bir değişiklik yapmamış olurum.

Liskov substitution principle;

Alt sınıflar miras aldığı üst sınıfın bütün özelliklerini kullanmalı, alt sınıflarda oluşturulan nesneler üst sınıfların nesneleriyle yer değiştirdiklerinde aynı davranışı göstermeli ve herhangi bir kullanılmayan özellik olmamalıdır. Bu ilkeye göre "türetilmiş veya alt sınıflar, temel veya ebeveyn sınıflarının yerine geçebilir." Bu ilke ana sınıfın alt sınıfı olan herhangi bir sınıfın, beklenmedik davranışları olmaksızın ata sınıf yerine kullanılmasını sağlar.

Bir çiftçinin oğlu çiftçilik özelliklerini babasından alması ve gerektiğinde babasının yerine geçmesi bu duruma örnektir. Ama oğul boksör olmak istiyorsa aynı aile hiyerarşisine dahil olmasına rağmen babasının yerini almayacaktır.

Interface segregation principle;

Bu prensip SOLİD'deki sınıflar yerine arayüzler interfaceler için gerçerli olan ilk prensiptir ve SRP-LSP prensiplerine benzemektedir. Bu ilke özet olarak şunu söyler "Hiçbir concrete sınıf kendisi ile ilgisi olmayan bir özelliği içeren arayüzden implemente edilmemelidir ". Burada asıl amacımız interfacelerin şişirilmesinden kaçınmamız olmasıdır. Tek bir interface yerine optimum özellikli birçok arayüz tercih edilmelidir.

Dipendencey Inversion Prensbles

Bu ilkede yüksek seviyeli sınıflar düşük seviyeli modüllere bağlı olmamalıdır. Modül ve sınıflar soyutlamalara bağlı olmalıdır. Soyutlamalar detaylara bağlı olmamalıdır. Detaylar soyutlara bağlı olmalıdır. Bu detaydan kasıt sınıflara yüklenen görevlerdir. Bu ilkenin en can alıcı noktası bir sınıfın eylem yürütmek için kullandığı araçlar ile birleştirilmemesi gerektiğidir. ancak arayüzün teknik özelliklerini karşılaması gerekir. Yani methodlar aldığı parametleri karşılaması gerekir. Somut sınıflar soyut sınıflara, soctyut sınıflarda UI katmanına bağlı olmalıdır böylece bağımlılık en az seviye indirilir ve bu bağlar oluşturulurken inject yöntemleri kullanılır.

Yukarıdaki satırlara basitçe değinmek gerekirse yüksek seviyeli bir modülün veya sınıfın düşük seviyeli modüllere veya sınıflara daha fazla bağımlı olması durumunda ilgili sınıfların yani child-parent sınıfların birbirlerine sıkı sıkıya bağlı olduğu durumda bir sınıfta bir değişiklik yapıldığında yada yapmaya çalışıldığında bundan kaç sınıf etkilendiği yani kaç sınıfta değişikliği yerine getirmektiğini belirtir. Bu bağlamda alt sınıfları soyut ata sınıflara bağlamalıyız.

Somut bir örnek vermek gerekirse bir televizyon kumandası düşünelim, uzaktan kumandanın pile ihtiyacı vardır, ancak pil markasına bağımlı değildir. İstediğimiz herhangi bir pil markasını kullanabiliriz ve bu bağlamda TV uzaktan kumandasının marka adıyla gevşek bağlı bir şekilde eşleştiğini söyleyebiliriz.

Dependency Injection;

Dependency Injection, S.O.L.I.D prensiplerinin 5'inci özelliği olan “Dependency Inversion” prensibinin uygulanış biçimidir denilebilir.

Nesneye yönelik programlama dillerinde bir nesne oluşturulur ve bu nesne görevini yaparken diğer nesnelerle iletişim halindedir. Classlar birbiri içlerinde new operatörüyle oluşturulup kullanılabilir. Bu yöntem katı bir bağımlılık oluşturmaktadır. Özet olarak; Dependency Injection tekniğinde bağımlılık oluşturacak parçalarının ayrılıp, bunların sisteme dışarıdan verilmesi (enjekte edilmesi) ile bağımlılığın en aza indirilmesiyle meydana gelir.

3 temel Dipendency Injection yöntemi vardır;

interface IAraba ==>//İnterface tnaımlandı
{
    byte TekerSayisi { get; set; }
    Color Renk { get; set; }
    string Model { get; set; }
    string Marka { get; set; }
}
class Renault : IAraba
{
    public Renault(string marka, string model, Color renk, byte tekerSayisi)
    {
        Marka = marka;
        Model = model;
        Renk = renk;
        TekerSayisi = tekerSayisi;
    }
 
    public string Marka { get; set; }
    public string Model { get; set; }
    public Color Renk { get; set; }
    public byte TekerSayisi { get; set; }
}
 
class Fiat : IAraba
{
    public Fiat(string marka, string model, Color renk, byte tekerSayisi)
    {
        Marka = marka;
        Model = model;
        Renk = renk;
        TekerSayisi = tekerSayisi;
    }
 
    public string Marka { get; set; }
    public string Model { get; set; }
    public Color Renk { get; set; }
    public byte TekerSayisi { get; set; }
}
  • Constructor Injection;

class AracYonetimi ==> Constructor Injection un kullanım yeri.
==>Burada direk sınıfları ipmlement etmek yerine injection yöntemi kullanarak
==>işlemi yapıyoruz
{
    readonly IAraba _araba;             ==> Bu kısım injection. 
 
    public AracYonetimi(IAraba araba)   ==> Interface, Arac kullanımı class ına 
    {
        _araba = araba;                 ==> Cunstroctor method ile Inject ediliyor.
    }
 
    public void RenkDegistir(Color renk) => _araba.Renk = renk;
 
    public void ModelDegistir(string model) => _araba.Model = model;
 
    public void TekerSayisiDegistir(byte tekerSayisi) => _araba.TekerSayisi = tekerSayisi;
 
    public string TumOzellikler()
    {
        var arry = new string[4];
        arry[0] = $"{nameof(_araba.TekerSayisi)}:{_araba.TekerSayisi}";
        arry[1] = $"{nameof(_araba.Renk)}:{_araba.Renk}";
        arry[3] = $"{nameof(_araba.Marka)}:{_araba.Marka}";
        arry[2] = $"{nameof(_araba.Model)}:{_araba.Model}";
        return string.Join(Environment.NewLine, arry);
    }
}
==> Program.CS çalıştırılacağı yer

var aracYonetimi = new AracYonetimi(new Fiat("Fiat", "500L", Color.Red, 2));
WriteLine(aracYonetimi.TumOzellikler());
ReadLine();
TekerSayisi:2
Renk:Color [Red]
Model:500L
Marka:Fiat
  • Property Injection


class AracYonetimi ==> Property Injection un kullanım yeri
{
    public IAraba Araba { get; set ; } ==> Injection burada yapılıyor. 
                                       ==>Inteface bu class a inject ediliyor
 
    public void RenkDegistir(Color renk) => Araba.Renk = renk;
 
    public void ModelDegistir(string model) => Araba.Model = model;
 
    public void TekerSayisiDegistir(byte tekerSayisi) => Araba.TekerSayisi = tekerSayisi;
 
    public string TumOzellikler()
    {
        var arry = new string[4];
        arry[0] = $"{nameof(Araba.TekerSayisi)}:{Araba.TekerSayisi}";
        arry[1] = $"{nameof(Araba.Renk)}:{Araba.Renk}";
        arry[3] = $"{nameof(Araba.Marka)}:{Araba.Marka}";
        arry[2] = $"{nameof(Araba.Model)}:{Araba.Model}";
        return string.Join(Environment.NewLine, arry);
    }
}

var aracYonetimi = new AracYonetimi
{
    Araba = new Fiat("Fiat", "500L", Color.Red, 2)
};
aracYonetimi.TekerSayisiDegistir(4);
aracYonetimi.ModelDegistir("500X");
aracYonetimi.RenkDegistir(Color.Blue);
 
WriteLine(aracYonetimi.TumOzellikler());
  • Method Injection

class AracYonetimi
{
 
    public void RenkDegistir(IAraba araba, Color renk) => araba.Renk = renk;
 
    public void ModelDegistir(IAraba araba, string model) => araba.Model = model;
 
    public void TekerSayisiDegistir(IAraba araba, byte tekerSayisi) => araba.TekerSayisi = tekerSayisi;
 
    public string TumOzellikler(IAraba araba)
    {
        var arry = new string[4];
        arry[0] = $"{nameof(araba.TekerSayisi)}:{araba.TekerSayisi}";
        arry[1] = $"{nameof(araba.Renk)}:{araba.Renk}";
        arry[3] = $"{nameof(araba.Marka)}:{araba.Marka}";
        arry[2] = $"{nameof(araba.Model)}:{araba.Model}";
        return string.Join(Environment.NewLine, arry);
    }
}

var aracYonetimi = new AracYonetimi();
var araba = new Fiat("Fiat", "500L", Color.Red, 2);

aracYonetimi.TekerSayisiDegistir(araba, 4);
aracYonetimi.ModelDegistir(araba, "500X");
aracYonetimi.RenkDegistir(araba, Color.Blue);

WriteLine(aracYonetimi.TumOzellikler(araba));
Robert C. Martins
SOLID Principles