- Single Responsibility Principle (اصل مسئولیت واحد) :
هرکلاسی فقط باید یه کار انجام بده و فقط باید به یه دلیل تغییر کنه
- Open-Closed Principle (اصل باز و بسته) :
اگر من یه روزی بخوام ویژگی جدیدی به کلاسم اضافه کنم بتونم خیلی راحت و بدون دستکاری کد اصلی این کار رو انجام بدم.
در واقع مفهومش استفاده از Interface و Implement کردن در کلاس های دیگه که قرار دستخوش تغییر بشن
- Liskov Substitution Principle (اصل جایگزینی لیسکوف) :
یعنی اگر کلاس A داشتیم و خواستیم بعد مدتی گسترشش بدیم و ی سری ویژگی ها بهش اضافه کنیم،پس باید ی کلاس دیگه بسازیم به اسم B که از کلاس A رو اکستند (extend) کنه (کلاس B ارث بری کنه از A) باید این قدر جامع باشه که هر رفتاری که کلاس B انجام میدهد از کلاس A مشتق شده باشد
- Interface Segregation Principle (اصل تفکیک رابط) :
کلاس ها نباید مجبور باشن متد هایی که به آن ها احتیاج ندارند رو پیاده سازی کنند ، مثلا اگر دو کلاس از یک Interface پیروی میکنند که در اون متدی وجود دارد که نیازی به یکی از آن ها را ندارد پس نباید از آن ارث بری کند و باید یک Interface جدا براش در نظر گرفته شود.
- Dependency Inversion Principle (اصل تفکیک رابط) :
کلاس ها ی سطح بالا نباید به کلاس های پایین دسترسی داشته باشند.
اصول SOLID مجموعهای از پنج قانون طراحی شیگرا هستند که به توسعهدهندگان کمک میکنند تا کدهای خود را با کیفیت بالاتری بنویسند. در اینجا این پنج اصل را با توضیحات و مثالهای کد C# توضیح میدهیم:
1. Single Responsibility Principle (SRP)
هر کلاس فقط باید یک مسئولیت داشته باشد و این مسئولیت کاملاً مشخص باشد.
مثال:
public class Employee
{
public string Name { get; set; }
public double Salary { get; set; }
public double CalculateBonus()
{
return Salary * 0.1;
}
}
public class EmployeeRepository
{
public void Save(Employee employee)
{
// کد مربوط به ذخیرهسازی کارمند در پایگاه داده
}
}
در این مثال، کلاس Employee
فقط مسئول اطلاعات و عملیات مربوط به کارمند است و کلاس EmployeeRepository
مسئول ذخیرهسازی کارمند است.
2. Open/Closed Principle (OCP)
کلاسها باید برای توسعه باز و برای تغییر بسته باشند. به عبارت دیگر، باید بتوانیم کلاسها را بدون تغییر در کد موجود توسعه دهیم.
مثال:
public abstract class Employee
{
public string Name { get; set; }
public double Salary { get; set; }
public abstract double CalculateBonus();
}
public class PermanentEmployee : Employee
{
public override double CalculateBonus()
{
return Salary * 0.1;
}
}
public class TemporaryEmployee : Employee
{
public override double CalculateBonus()
{
return Salary * 0.05;
}
}
در این مثال، کلاس Employee
برای اضافه کردن نوعهای جدید از کارمندان باز است، اما نیازی به تغییر در کلاسهای موجود ندارد.
3. Liskov Substitution Principle (LSP)
کلاسهای مشتق باید بتوانند جایگزین کلاسهای پایه خود شوند بدون اینکه رفتار برنامه تغییر کند.
مثال:
public abstract class Shape
{
public abstract double Area();
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area()
{
return Width * Height;
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
public void DisplayArea(Shape shape)
{
Console.WriteLine(shape.Area());
}
در این مثال، میتوانیم از هر کلاس مشتق شده از Shape
استفاده کنیم و متد Area
بدون مشکل کار خواهد کرد.
4. Interface Segregation Principle (ISP)
کلاسها نباید مجبور به پیادهسازی اینترفیسهایی باشند که از آنها استفاده نمیکنند. اینترفیسها باید کوچک و ویژه باشند.
مثال:
public interface IWorker
{
void Work();
}
public interface IEater
{
void Eat();
}
public class Worker : IWorker, IEater
{
public void Work()
{
Console.WriteLine("Working...");
}
public void Eat()
{
Console.WriteLine("Eating...");
}
}
public class Robot : IWorker
{
public void Work()
{
Console.WriteLine("Working...");
}
}
در این مثال، کلاس Robot
فقط نیاز به پیادهسازی متد Work
دارد و نیازی به پیادهسازی متدهای غیرضروری ندارد.
5. Dependency Inversion Principle (DIP)
ماژولهای سطح بالا نباید به ماژولهای سطح پایین وابسته باشند. هر دو باید به انتزاعها وابسته باشند. انتزاعها نباید به جزئیات وابسته باشند، بلکه جزئیات باید به انتزاعها وابسته باشند.
مثال:
public interface IMessageSender
{
void SendMessage(string message);
}
public class EmailSender : IMessageSender
{
public void SendMessage(string message)
{
// کد مربوط به ارسال ایمیل
}
}
public class Notification
{
private readonly IMessageSender _messageSender;
public Notification(IMessageSender messageSender)
{
_messageSender = messageSender;
}
public void Notify(string message)
{
_messageSender.SendMessage(message);
}
}
در این مثال، کلاس Notification
به کلاسهای سطح پایین (مانند EmailSender
) وابسته نیست، بلکه به اینترفیس IMessageSender
وابسته است. این باعث میشود تا به راحتی بتوان کلاسهای جدید برای ارسال پیام ایجاد کرد و از آنها استفاده کرد بدون نیاز به تغییر در کلاس Notification
.