DEV Community

a1excpunk
a1excpunk

Posted on

Understanding SOLID Principles with C# (short intro)

The SOLID principles are a set of design guidelines in object-oriented programming aimed at creating robust, maintainable, and scalable software. Coined by Robert C. Martin (Uncle Bob), these principles help developers avoid common pitfalls and write cleaner code.

S: Single Responsibility Principle (SRP)

Definition: A class should have only one reason to change.

Explanation: Each class should focus on a single responsibility or functionality. This makes code easier to understand, test, and maintain.

Example:

Instead of creating a User class that handles data storage and email notifications, split it into User for managing user data and EmailService for handling email notifications.

public class UserService 
{ 
    public void AddUser(string name) 
    { 
       // Implement logic 
    } 
}

public class EmailService 
{ 
    public void SendEmail(string email) 
    { 
        // Implement logic 
    } 
}

Enter fullscreen mode Exit fullscreen mode

O: Open/Closed Principle (OCP)

Definition: Classes should be open for extension but closed for modification.

Explanation: Code should allow new functionality to be added without altering existing code. This promotes stability and reduces the risk of bugs.

Example:

Instead of modifying a class to add a new type of payment method, use interfaces or inheritance to extend functionality.

public interface IPayment 
{ 
    void Pay(); 
}

public class CardPayment : IPayment 
{ 
    public void Pay() 
    { 
        // Card payment 
    } 
}

public class PaymentProcessor 
{ 
    public void Process(IPayment payment) 
    { 
        payment.Pay(); 
    } 
}

Enter fullscreen mode Exit fullscreen mode

L: Liskov Substitution Principle (LSP)

Definition: Subtypes must be substitutable for their base types without altering the correctness of the program.

Explanation: If a class B is a subclass of class A, then objects of type A should be replaceable with objects of type B without breaking the application.

Example:

If Rectangle is a superclass and Square inherits from it, ensure the subclass doesn’t alter behavior, such as how dimensions are set.

public interface IShape 
{ 
    int Area(); 
}

public class Rectangle : IShape 
{ 
    public int Area() => Width * Height; 
}

public class Square : IShape 
{ 
    public int Area() => Side * Side; 
}

Enter fullscreen mode Exit fullscreen mode

I: Interface Segregation Principle (ISP)

Definition: A class should not be forced to implement interfaces it does not use.

Explanation: Split large interfaces into smaller, more specific ones. This ensures classes implement only what they need.

Example:

Instead of one large Animal interface with methods like Fly(), Swim(), and Run(), create specific interfaces like Flyable, Swimmable, and Runnable.

public interface IFlyable 
{ 
    void Fly(); 
}

public interface IWalkable 
{ 
    void Walk(); 
}

public class Bird : IFlyable, IWalkable 
{ 
    public void Fly() 
    { 
        // Flying logic 
    }

    public void Walk() 
    { 
        // Walking logic 
    } 
}

Enter fullscreen mode Exit fullscreen mode

D: Dependency Inversion Principle (DIP)

Definition: High-level modules should not depend on low-level modules; both should depend on abstractions.

Explanation: Rely on abstractions rather than concrete implementations to reduce coupling between components.

Example:

Instead of hardcoding a SQLDatabase in a class, use an interface like IDatabase, allowing easy switching to other databases (e.g., NoSQL).

public interface IDatabase 
{ 
    void Save(string data); 
}

public class SQLDatabase : IDatabase 
{ 
    public void Save(string data) 
    { 
        // Save to SQL 
    } 
}

public class DataManager 
{ 
    public DataManager(IDatabase db) 
    { 
        db.Save("data"); 
    } 
}

Enter fullscreen mode Exit fullscreen mode

Why Use SOLID?

  1. Better Maintainability: Easier to understand and modify code.
  2. Scalability: Adapts well to new features or requirements.
  3. Reduced Bugs: Minimizes side effects when changes are made.
  4. Reusability: Code can be reused across projects.

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more