SOLID Principle in ProgrammingThe SOLID principles are a set of guidelines for writing maintainable and scalable software. They are:
- Single Responsibility Principle (SRP)
- Open-Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
Single Responsibility Principle (SRP):A class should have only one reason to change. The Single Responsibility Principle (SRP) states that a class should have only one reason to change. This means that a class should have a single, well-defined responsibility and should only have the necessary methods and data to fulfil that responsibility.
For example, let's say you have a class called "Order" that represents an order in an e-commerce application. The Order class might have the following responsibilities:
- Storing information about the order (e.g. customer information, items in the order, total cost)
- Calculating the total cost of the order
- Persisting the order to a database
- Sending an email to the customer to confirm the order
- An "Order" class that only stores information about the order
- A "OrderCalculator" class that only calculates the total cost of the order
- An "OrderPersistor" class that only persists the order to a database
- An "EmailSender" class that only sends an email to the customer
Open-Closed Principle (OCP):A class should be open for extension but closed for modification. The Open-Closed Principle (OCP) states that a class should be open for extension but closed for modification. This means that a class should be designed in such a way that it can be extended to add new functionality without modifying its existing code. One way to achieve this is by using inheritance and polymorphism. For example, let's say you have a class called "Shape" that represents a shape in a drawing application. The Shape class might have a method called "Draw" that is used to draw the shape on the screen.
To extend the functionality of the Shape class to support new types of shapes, you could create subclasses for each new shape (e.g. "Circle", "Rectangle", "Triangle"). Each of these subclasses would inherit from the Shape class and override the "Draw" method to provide the specific functionality for that shape.
This way, the Shape class remains closed for modification (i.e. you don't need to change the Shape class to add new shapes), but is open for extension (i.e. you can create new subclasses to add new shapes).Another way of achieving Open-Closed Principle is by using interfaces and composition. For example, let's say you have a class called "Shape" that has a method called "Draw" that is used to draw the shape. Instead of having the class contain the specific implementation of the Draw method, you could create an interface called "IDrawable" that defines the Draw method, and have the class implement this interface. This way, if you need to add a new way of drawing the shape (for example, adding support for 3D shapes), you could create a new class that implements the IDrawable interface and use it in the shape class without modifying the existing code.
This way, the shape class is open to extension and can easily adapt to new requirements without modifying the existing code.
Liskov Substitution Principle (LSP):Subtypes should be able to replace their base types without affecting the correctness of the program. The Liskov Substitution Principle (LSP) states that subtypes should be able to replace their base types without affecting the correctness of the program. In other words, if a program is using a base class, it should be able to use any of its subclasses without knowing it, and the program's behaviour should not change. To illustrate this principle, let's say you have a class called "Bird" and a subclass called "Penguin". The "Bird" class has a method called "Fly" that makes the bird fly. Now, if you create a "Penguin" class that inherits from "Bird", you should not be able to make the penguin fly. So, you could override the Fly method in the Penguin class and make it throw an exception or display a message "I can't fly".
Interface Segregation Principle (ISP)A class should not be forced to implement interfaces it does not use. The Interface Segregation Principle (ISP) states that a client should not be forced to implement interfaces it does not use. In other words, it's better to have many small, specific interfaces than a few large, general interfaces.
To illustrate this principle, let's say you have a class called "Printer" that should implement an interface called "PrintingDevice". The interface defines several methods, including "Print", "Scan", "Fax", and "Copy". But let's say that the Printer class only needs to implement the "Print" method and doesn't need to implement the other methods in the interface.
According to Interface Segregation Principle, it would be better to create a new interface called "PrintableDevice" that contains only the "Print" method and have the Printer class implement this new interface. This way, the Printer class is not forced to implement methods that it does not need, making the code more flexible and easier to maintain. ISP is useful because it helps to keep interfaces small and specific, making them more focused and easier to understand. It also makes the code more flexible and maintainable, as classes are only required to implement the methods that they actually need. This way, when a class needs to be modified or extended, it is only necessary to modify the specific interface that the class implements, rather than modifying a large and general interface.
Dependency Inversion Principle (DIP)High-level modules should not depend on low-level modules, but both should depend on abstractions. The Dependency Inversion Principle (DIP) states that high-level modules should not depend on low-level modules, but both should depend on abstractions. In other words, it's better to depend on abstractions rather than concretions.
To illustrate this principle, let's say you have a class called "Order" that needs to process payments. The Order class has a method called "ProcessPayment" that takes a "PaymentProcessor" object as a parameter. The PaymentProcessor class is a low-level class that handles the details of processing payments.
According to Dependency Inversion Principle, it would be better to create an abstraction (an interface or an abstract class) called "IPaymentProcessor" that defines the methods that the PaymentProcessor class implements. The Order class should then depend on this abstraction rather than the PaymentProcessor class. This way, if you need to change the way payments are processed, you only need to change the PaymentProcessor class and its corresponding test, without affecting the Order class. Dependency Inversion Principle is useful because it helps to decouple high-level modules from low-level modules, making the code more flexible and maintainable. It also makes the code more testable, as it's easier to test high-level modules in isolation when they depend on abstractions rather than concretions. Dependency Inversion Principle is closely related to the Dependency Injection pattern, which is a technique to implement Dependency Inversion Principle by injecting the dependencies of a class through its constructor or methods, rather than creating them within the class. This makes the class more flexible and maintainable, as it can be easily configured with different implementations of the dependencies.
- What is object-oriented programming?
- What is a Class?
- What is an Object?
- Constructors and Destructors
- What Is Inheritance ?
- What are the different types of inheritance ?
- What are Access Modifiers ?
- Why Classes cannot be declared as Protected?
- Can we declare private class in namespace
- Difference between Classes and Structures
- Can we use pointers in C# ?
- Why abstract class can't create instance
- Can you prevent your class from being inherited
- Difference between method Overloading and Overriding
- Difference between Early Binding and Late binding
- What is nested class
- What is partial class ?
- What is Virtual Method
- Difference between class and object
- What is Data Encapsulation?
- Object Based Language and OOPs
- Solid Principles | Advantages and Disadvantages