SOLID Principles
In Object-Oriented Programming (OOP)
Concept, SOLID principles are the acronym for five Object-Oriented Design
(OOD) principles. These SOLID principles are used to improve the
understand-ability, flexibility and maintainability of the code.
S.O.L.I.D. Stands For?
1. S - Single-responsibility principle
2. O - Open-closed principle
3. L - Liskov substitution principle
4. I - Interface segregation principle
5. D - Dependency Inversion Principle
Let’s see what is the exact meaning of
each principle using an example.
Ex: There is an online store. A
registered customer can place an order and purchase them using the card or make
payment when delivering the order. Let’s move to the principles again.
1.
Single-Responsibility
Principle
The common definition of this principle is “A class
should have one and only one reason to change, meaning that a class should have
only one job.” When we consider the above online store, there is a class called
“Customer”. This customer class should only contain the customer
createCustomer(), retrieveCustomer(), updateCustomer() and deleteCustomer()
methods. placeOrder() is not a method of the Customer class.
According to the single-responsibility principle,
we can only use the methods and attributes that are actively regarding that
particular class.
2.
Open-Closed Principle
The common definition of this principle is “Objects
or entities should be open for extension, but closed for modification.” When
considering the above online store, it has a payment method using card or cash.
We can create an Order class and use if-else statements to find the payment
type. If we have to include wallets as another type of payment, we should edit
the code. So, we violate the
“closed for modification”. As a solution for that we can use interfaces.
We can create a Payment interface with
savePayment() method and implement the interface as CashPayment, CardPayment
and WalletPayment. Using the interface code can extend avoiding the
modification.
3.
Liskov Substitution Principle
The common definition of this principle is “Let
q(x) be a property provable about objects x of type T. Then q(y) should be
provable for objects y of type S where S is a subtype of T.” The children
classes should be able to substitute the parent for providing the functionality
promised by the parent in a meaningful way is the simple idea of the
definition.
Let's assume the Order class is a parent class and it has two
children classes named CashOnDeliveryOrder and OnlinePaymentOrder. Order class
has a method savePayment() and both children classes should be able to use
it.
4.
Interface Segregation Principle
The common definition of this principle is “A
client should never be forced to implement an interface that it doesn't use or
clients shouldn't be forced to depend on methods they do not use.” Let’s consider the above online store’s Payment
interface. We need to store credit card information in a separate table and we
create a separate method saveCardDetails() in the Payment interface. Now the
class CashPayment has to implement both saveCardDetails() and
savePayment().
So, it is a violation
of “a client should never be forced to implement an interface that it doesn't
use”. So we can create another separate interface named CardPayment to
implement saveCardDetails()method. Now, CashPayment can implement only the
Payment interface and CardPayment can implement both Payment and CardPayment
interfaces.
5.
Dependency Inversion Principle
The common definition of this principle is “Entities must depend on
abstractions not on concretions. It states that the high-level module must not
depend on the low- level module, but they should depend on abstractions.” Simple meaning of this is “The
responsibility of creating the dependent object should be outsourced to that of
consuming class”.
Let’s consider the Order class of the online store example. The responsibility of the payment type is a responsibility of Driven class and not a responsibility of Order class. The Driven class should select the payment type to continue the order.
Class Order{
Customer c;
Payment p;
Order (Customer c, Payment p){
this.c = c;
this.p = p;
}
save_Payment(){
p.savePayment();
}
}
Now, we can call the above Order class (a sample class for explaining) using different customers and payment types. Driven class can access the order using following way.
Order order = new Order ( customer , new CashPayment())
Comments
Post a Comment