Yazılımcıların bilmesi gereken SOLID Prensipleri, Robert C. Martin (Bob Amca) tarafından Design Principles and Patterns kitabında tanıtılmış olup yazılımı daha anlaşılır ve okunabilir, geliştirilebilir, esnek ve bakımı kolay ve kod tekrarını önlemek için geliştirilmiş prensipler bütünüdür. 5 farklı prensipten oluşmakta ve baş harfleri ile kendi tanımlarını içermektedir.
Single Responsibility Princible (SRP)
Bir sınıf (Class) veya metodun üstlenebileceği tek bir sorumluluk olması gerekmektedir. Farklı görevleri üstlenmemesi gerekir.
Bir ürün sınıfımız olduğunu düşünelim. İçerisinde ürün ve rapor oluşturan iki farklı metodumuz olduğunu düşünelim. SRP’ye göre rapor oluşturmak için yazılan metodumuzun burada olmaması gerekir.
public class Product
{
public int EProductId { get; set; }
public string Name { get; set; }
public void CreateProduct(Product product)
{
//Product created!
}
public void CreateReport(Product product)
{
//Report is taken with this method
}
}
Tekrar düzenlediğimizde ise farklı bir sınıf içerisine alarak bu prensibin gereksinimini yerine getirmiş olmaktayız.
public class Report
{
public void CreateReport(Product product)
{
//Report Created
}
}
Open-Closed Princible (OSP)
Bu prensibe göre sınıflarımız gelişime karşı ılımlı yaklaşırken, değişime karşı sıcak yaklaşmamalıdır. Örneğin; Ahmet adında bir arkadaşımızın makas şeklinde bir eli olsun. Onunla kesme işlemini çok rahat bir şekilde yapabilmektedir. Fakat zarar vermeden bir şeyleri tutmak istediğinde, ona veya diğer isteklerine göre sürekli yeni aparatlar ile desteklemelidir. Fakat Ahmet’in normal elleri olsa idi, aslında doğası gereği istediği çoğu şeye ayak uydurabilecek bir sistemi olacaktı.
Eğer ki yukarıdaki ürün örneğimizden gidecek olursak, istenilen raporların formatlarını bilmemekle beraber değişiklik gösterebileceğini öngörebiliriz. Eğer aşağıdaki gibi bir kod bloğu yazarsak ileride gelebilecek farklı dosya formatlarını ayrı bir “if” bloğu eklememiz gerekecek.
public void CreateReport(Product product)
{
if (FileType == "Csv")
{
//Create Report with csv format
}
if (FileType == "Pdf")
{
//Create Report with pdf format
}
}
Kod bloğunu bu prensibe göre düzenlediğimizde ise aşağıdaki gibi yapı oluşacaktır.
abstract class Report
{
public abstract void CreateReport();
}
class CSVReport : Report
{
public override void CreateReport()
{
//csv format
}
}
class PDFReport : Report
{
public override void CreateReport()
{
//pdf format
}
}
Liskov Substituion (LSP)
Temel olarak söylemek gerekirse kalıtım alan tüm sınıfların, aldıkları tüm özellikleri kullanabiliyor olmasıdır. Kullanmayacağı veya kullanamadığı kısımları almaması veya ona göre dizayn edilmesi gerekir.
Araçlarımızın kullandığını düşündüğümüz, hareket yönlerini için metot barındıran bir sınıfımız olduğunu düşünelim. Bunları araba ve tren sınıfımıza kalıtımla verdiğimizde, trenin aslında sağa ve sola dönemediğini bilmekteyiz.
public abstract class MovementtDirection
{
public virtual void TurnRight()
{
// to turn right
}
public virtual void Forward()
{
//to go ahead
}
}
public class Train : MovementtDirection
{
public override void Forward()
{
// forward
}
public override void TurnRight()
{
//throw exception - has no behaviour like this
}
}
public class Car : MovementtDirection
{
public override void Forward()
{
// forward
}
public override void TurnRight()
{
//to right
}
}
Eğer gerekli düzenlemeleri yaparsak, hareket yönlerimizi aşağıdaki gibi ayırmamız gerekmektedir.
//We can imagine that 2D and XLine(bakward-forward) -- YLine(right-left)
public abstract class XLineDirection
{
public virtual void Forward()
{
//to go ahead
}
}
interface IYLineDirection
{
void TurnRight();
}
public class Train : XLineDirection
{
public override void Forward()
{
// forward
}
}
public class Car : XLineDirection, IYLineDirection
{
public override void Forward()
{
// forward
}
public void TurnRight()
{
//to right
}
}
Interface Segregation Principle (ISP)
Bu prensibe göre, her arayüz kendi görevlerini yerine getirecek şekilde dizayn edilmedilir. Farklı metod gruplarını barındırarak yük olması istenmez. Sınıfların gerekli olanları alması istenerek, ihtiyaçları olmayan metotların taşınmaması gerekir.
interface IPost
{
void CratePost();
void ReadPost();
}
Bu ara yüzümüzü bir sınıfa implemente ettiğimizde, ReadPost kısmını kullanmayacağını varsayalım. Bu durumda ara yüzleri parçalamamız gerekmektedir.
interface IPostCreate
{
void CreatePost();
}
interface IReadPost
{
void ReadPost();
}
Dependency Inversion Principle (DIP)
Robert C. Martin’in Dependency Inversion Prensibi’ne göre;
- Üst seviye (High-Level) sınıflar, alt seviye (Low-Level) sınıflara bağlı olmamalıdır, ilişki abstraction veya interface kullanarak sağlanmalıdır,
- Abstraction(soyutlama) detaylara bağlı olmamalıdır, tam tersi detaylar abstraction(soyutlama)’lara bağlı olmalıdır.
Bir sohbet odası içerisinde send metodumuz olduğunu düşünelim. SendText metodumuz burada üst seviye bir sınıfa bağlıdır. İleride herhangi bir parça eklediğimizde veya değiştirdiğimizde, bir çok kısımda gereğinden fazla değişiklik yapmış olacağız.
public class ChatRoom
{
//High Level
public void Send()
{
Message message = new Message();
message.SendText(true);
}
}
public class Message
{
//Low Level
public void SendText(bool isText)
{
//Process
}
}
Burada bağımlılıktan kurtarmak için bu kodu aşağıdaki gibi düzenlememiz gerekmektedir.
interface IContent
{
void SendText(bool text);
}
class Blog
{
//High Level Class
IContent content;
public Blog()
{
content = new Message();
}
public void Send()
{
content.SendText(true);
}
}
class Message : IContent
{
//Low Level Method
public void SendText(bool text)
{
//Process
}
}
Solid prensiplerinin 5 maddesine de kısa bir şekilde göz atmış olduk. Umarım faydalı bir yazı olmuştur.

Yorum Yap