NOT : Bu yazıyı chatgpt yazmıştır! * SOLID, yazılım mühendisliğinde nesne yönelimli tasarım (OOD) ilkeleri olarak bilinen beş temel prensipten oluşur. Bu prensipler, yazılımın esnekliğini, bakımı ve genişletilebilirliğini artırmaya yardımcı olur. Aşağıda her bir SOLID prensibine ilişkin örnekler ve açıklamalar yer almaktadır.
1. Single Responsibility Principle (SRP) - Tek Sorumluluk Prensibi
Bir sınıf yalnızca bir iş sorumluluğuna sahip olmalıdır.
Açıklama: Bir sınıf birden fazla sorumluluğa sahip olursa, bu sınıfın değişmesi gereken durumlar arttıkça diğer sorumluluklar da etkilenebilir. Bu da yazılımın bakımını zorlaştırır.
Örnek:
// SRP ihlali - Bir sınıf hem veri kaydeder hem de loglama yapar
public class UserService
{
public void RegisterUser(User user)
{
// Kullanıcı kaydetme işlemleri
}
public void Log(string message)
{
// Loglama işlemleri
}
}
// SRP ile uyumlu - Sadece kullanıcı kaydeder, loglama başka bir sınıfta yapılır
public class UserService
{
private readonly ILogger _logger;
public UserService(ILogger logger)
{
_logger = logger;
}
public void RegisterUser(User user)
{
// Kullanıcı kaydetme işlemleri
}
}
public interface ILogger
{
void Log(string message);
}
public class FileLogger : ILogger
{
public void Log(string message)
{
// Dosyaya log yazma işlemi
}
}
2. Open/Closed Principle (OCP) - Açık/Kapalı Prensibi
Yazılım varlıkları (sınıflar, modüller, fonksiyonlar) genişlemeye açık, ancak değişikliğe kapalı olmalıdır.
Açıklama: Bir sınıfın işlevselliği eklenebilir, ancak mevcut sınıfı değiştirmemelidir. Bu, sınıfın üzerine yeni işlevsellik eklemeyi kolaylaştırır.
Örnek:
// OCP ihlali - Yeni özellik eklemek için mevcut sınıfı değiştiriyoruz
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
public class AreaCalculator
{
public double CalculateArea(Rectangle rectangle)
{
return rectangle.Width * rectangle.Height;
}
public double CalculateArea(Circle circle)
{
return Math.PI * circle.Radius * circle.Radius;
}
}
// OCP ile uyumlu - Yeni şekiller eklenebilir, ancak mevcut sınıflar değiştirilmez
public interface IShape
{
double Area();
}
public class Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public double Area()
{
return Width * Height;
}
}
public class Circle : IShape
{
public double Radius { get; set; }
public double Area()
{
return Math.PI * Radius * Radius;
}
}
public class AreaCalculator
{
public double CalculateArea(IShape shape)
{
return shape.Area();
}
}
3. Liskov Substitution Principle (LSP) - Liskov Yerine Geçme Prensibi
Türetilmiş sınıflar, temel sınıflar yerine kullanılabilir olmalıdır.
Açıklama: Bir alt sınıf, temel sınıfın yerine geçebilmelidir. Yani alt sınıf, temel sınıfın tüm işlevselliğini sağlamalı ve temel sınıfla uyumlu olmalıdır.
Örnek:
// LSP ihlali - Alt sınıf temel sınıfın yerine geçemiyor
public class Bird
{
public virtual void Fly()
{
Console.WriteLine("Bird is flying");
}
}
public class Ostrich : Bird
{
public override void Fly()
{
// Deve kuşları uçamaz
throw new InvalidOperationException("Ostriches cannot fly");
}
}
// LSP ile uyumlu - Alt sınıf, temel sınıfın yerine geçebilir
public abstract class Bird
{
public abstract void Move();
}
public class Sparrow : Bird
{
public override void Move()
{
Console.WriteLine("Sparrow is flying");
}
}
public class Ostrich : Bird
{
public override void Move()
{
Console.WriteLine("Ostrich is running");
}
}
4. Interface Segregation Principle (ISP) - Arayüz Ayırma Prensibi
Kullanıcılar, kullanmadıkları metodlara bağlı kalmamalıdır.
Açıklama: Bir sınıfın sadece ihtiyaç duyduğu işlevleri içeren arayüzleri kullanması gerekir. Karmaşık ve genel arayüzlerden kaçınılmalıdır.
Örnek:
// ISP ihlali - Büyük ve karmaşık bir arayüz
public interface IWorker
{
void Work();
void Eat();
}
public class Worker : IWorker
{
public void Work()
{
// Çalışma işlemleri
}
public void Eat()
{
// Yemek yeme işlemleri
}
}
public class Robot : IWorker
{
public void Work()
{
// Robot çalışma işlemleri
}
public void Eat()
{
// Robotun yemek yemesi gereksiz
throw new NotImplementedException();
}
}
// ISP ile uyumlu - Küçük, spesifik arayüzler
public interface IWorkable
{
void Work();
}
public interface IEatable
{
void Eat();
}
public class Worker : IWorkable, IEatable
{
public void Work() { }
public void Eat() { }
}
public class Robot : IWorkable
{
public void Work() { }
}
5. Dependency Inversion Principle (DIP) - Bağımlılıkların Tersine Çevrilmesi Prensibi
Yüksek seviyeli modüller, düşük seviyeli modüllere bağımlı olmamalıdır. Her ikisi de soyutlamalara bağımlı olmalıdır.
Açıklama: Bağımlılıkların soyutlamalar üzerinden yapılması gerektiğini belirtir. Yüksek seviyeli sınıflar, düşük seviyeli sınıflara doğrudan bağımlı olmamalıdır.
Örnek:
// DIP ihlali - Yüksek seviyeli sınıf düşük seviyeli sınıfa doğrudan bağımlıdır
public class LightBulb
{
public void TurnOn() { }
public void TurnOff() { }
}
public class Switch
{
private LightBulb _bulb;
public Switch(LightBulb bulb)
{
_bulb = bulb;
}
public void Operate()
{
_bulb.TurnOn();
}
}
// DIP ile uyumlu - Soyutlamalar üzerinden bağımlılık
public interface ISwitchable
{
void TurnOn();
void TurnOff();
}
public class LightBulb : ISwitchable
{
public void TurnOn() { }
public void TurnOff() { }
}
public class Switch
{
private readonly ISwitchable _device;
public Switch(ISwitchable device)
{
_device = device;
}
public void Operate()
{
_device.TurnOn();
}
}