Definition: A class should have only one reason to change, meaning it should have a single, well-defined responsibility.
Think of a chef in a restaurant. A good chef focuses only on cooking - they don't take orders, serve tables, or handle payments. Each person has one clear responsibility.
// BAD: This class has multiple responsibilities
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
// Responsibility 1: Calculate pay
public decimal CalculatePay()
{
return Salary * 1.1m; // With bonus
}
// Responsibility 2: Save to database
public void SaveToDatabase()
{
// Database logic here
Console.WriteLine($"Saving {Name} to database...");
}
// Responsibility 3: Generate report
public void GenerateReport()
{
Console.WriteLine($"Employee Report: {Name} - ${Salary}");
}
// Responsibility 4: Send email
public void SendEmail(string message)
{
Console.WriteLine($"Sending email to {Name}: {message}");
}
}
Problems:
// GOOD: Each class has a single responsibility
public class Employee
{
public string Name { get; set; }
public string Email { get; set; }
public decimal Salary { get; set; }
}
public class PayrollCalculator
{
public decimal CalculatePay(Employee employee)
{
return employee.Salary * 1.1m; // With bonus
}
}
public class EmployeeRepository
{
public void Save(Employee employee)
{
Console.WriteLine($"Saving {employee.Name} to database...");
}
}
public class ReportGenerator
{
public void GenerateEmployeeReport(Employee employee)
{
Console.WriteLine($"Employee Report: {employee.Name} - ${employee.Salary}");
}
}
public class EmailService
{
public void SendEmail(Employee employee, string message)
{
Console.WriteLine($"Sending email to {employee.Email}: {message}");
}
}
Definition: Software entities should be open for extension but closed for modification.
Think of a smartphone. You can extend its functionality by installing new apps (open for extension) without modifying the phone's hardware or operating system (closed for modification).
// BAD: Need to modify existing code to add new shapes
public class AreaCalculator
{
public double CalculateArea(object shape)
{
if (shape is Rectangle rectangle)
{
return rectangle.Width * rectangle.Height;
}
else if (shape is Circle circle)
{
return Math.PI * circle.Radius * circle.Radius;
}
// To add a new shape, we must modify this method!
else if (shape is Triangle triangle)
{
return 0.5 * triangle.Base * triangle.Height;
}
throw new ArgumentException("Unknown shape");
}
}
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
public class Circle
{
public double Radius { get; set; }
}