SOLID Principle, a buzzword you hear everywhere, A brilliant rules to develop software.
What is SOLID Principle?
In object-oriented computer programming, SOLID is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible and maintainable. It is not related to the GRASP software design principles. The principles are a subset of many principles promoted by Robert C. Martin. Though they apply to any object-oriented design, the SOLID principles can also form a core philosophy for methodologies such as agile development or adaptive software development. The theory of SOLID principles was introduced by Martin in his 2000 paper Design Principles and Design Patterns, although the SOLID acronym itself was introduced later by Michael Feathers.
SOLID is made up of the first five principles in OOP, it stands for
- S - Single-responsibility principle
- O - Open-closed principle
- L - Liskov substitution principle
- I - Interface segregation principle
- D - Dependency inversion principle
Single-responsibility principle
Any class must have one and only one reason to change. In other words, a class must only have a single responsibility. This principle is simple, but not always easy to follow. It’s tempting to sneak new responsibilities into existing classes, but that’s likely to cause future issues. Save yourself time later, and make a new class now.
Incorrect Sample Single-responsibility principle:
class CustomerOrder {
public function createCustomer(Request $request) {
// Create customer
}
public function submitOrder(Request $request) {
// Submit Orders
}
}
Correct Sample Single-responsibility principle:
class Customer {
public function createCustomer(Request $request) {
// Create customer
}
}
class Order {
public function submitOrder(Request $request) {
// Submit Orders
}
}
Open-closed principle
Objects or entities must be open for extension but closed for modification. A class must be easily extensible without requiring modification of the class itself. The goal of this principle is to help create well-encapsulated, highly cohesive systems. We’ve found following the open-close rule really helps when multiple developers are involved—less system-specific domain knowledge is required to make updates and expansions.
Incorrect Sample of Open-closed principle:
class SavingAccount
{
public function CalculateInterest($accountType)
{
if($accountType=="Regular")
{
//Calculate interest for regular saving account
}
else if($accountType=="Salary")
{
//Calculate interest for saving account
}
}
}
Correct Sample of Open-closed principle:
interface ISavingAccount
{
public function CalculateInterest();
}
class RegularSavingAccount implements ISavingAccount
{
public function CalculateInterest()
{
//Calculate interest for regular saving account
}
}
class SalarySavingAccount implements ISavingAccount
{
public function CalculateInterest()
{
//Calculate interest for saving account
}
}
Liskov substitution principle
Derived types must be completely substitutable for their base types. New derived classes must just extend without replacing the functionality of old classes. Otherwise, the new classes can produce undesired effects if they’re used in existing program modules.
Incorrect Sample of Liskov substitution principle:
class Bird
{
public function Fly()
{
return “I can Fly”;
}
}
class Parrot extends Bird
{
public function Fly()
{
return “I can Fly”;
}
}
class Ostrich extends Bird
{
public function Fly()
{
return “I can Fly”;
// But ostrich can't fly
}
}
Correct Sample of Liskov substitution principle:
class Bird{
// Methods related to birds
}
class FlyingBirds extends Bird
{
public function Fly()
{
Return “I can Fly”;
}
}
class Parrot extends FlyingBirds{
public function Fly()
{
Return “I can Fly”;
}
}
class Ostrich extends Bird{
// Methods related to birds
}
Interface segregation principle
Clients must not be dependent upon interfaces or methods they don't use. Keeping interfaces segregated helps a developer more easily know which one to call for specific functions and helps us avoid fat or polluted interfaces that can affect the performance of a system. Doing so also helps us write better unit tests on the codebase.
Incorrect Sample of Interface segregation principle:
interface RestaurantInterface
{
public function acceptOnlineOrder();
public function payOnline();
public function walkInCustomerOrder();
public function payInPerson();
}
class OnlineClient implements RestaurantInterface
{
public function acceptOnlineOrder()
{
//logic for placing online order
}
public function payOnline()
{
//logic for paying online
}
}
Correct Sample of Interface segregation principle:
interface OnlineClientInterface
{
public function acceptOnlineOrder();
public function payOnline();
}
interface WalkInCustomerInterface
{
public function walkInCustomerOrder();
public function payInPerson();
}
class OnlineClient implements OnlineClientInterface
{
public function acceptOnlineOrder()
{
//logic for placing online order
}
public function payOnline()
{
//logic for paying online
}
}
class WalkInCustomer implements WalkInCustomerInterface
{
public function walkInCustomerOrder()
{
//logic for walk in customer order
}
public function payInPerson()
{
//logic for payment in person
}
}
Dependency inversion principle
High-level modules(component) must not depend on low-level modules. Both should depend on abstractions. abstractions should not depend on details. Details should depend on abstractions. This principle helps maintain a system that’s properly coupled. Avoiding high-level class dependencies on low-level classes helps keep a system flexible and extensible.
Incorrect Sample of Dependency inversion principle:
// Low Level Class
class PDFBook {
function read() {
return "reading a pdf book.";
}
}
// High Level Class
class EBookReader {
private $book;
function __construct(PDFBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
$book = new PDFBook();
$read = new EBookReader($b);
$read->read();
Correct Sample of Dependency inversion principle:
interface EBook{
function read();
}
// Low Level Class
class PDFBook implements EBook{
function read() {
return "reading a pdf book.";
}
}
// High Level Class
class EBookReader {
private $book;
function __construct(EBook $book) {
$this->book = $book;
}
function read() {
return $this->book->read();
}
}
$book = new PDFBook();
$read = new EBookReader($b);
$read->read();
Conclusion:
Using SOLID principles is critical to being a really good developer and creating valuable software solutions. SOLID is essentially a balanced nutrition plan for software development. When we don’t use these principles in development, our code base becomes bloated and overweight. The system then requires extra work and attention to “trim down” or even maintain, and is at much higher risk for an emergency scare.
Sample codes are available on my GitHub repo: https://github.com/yuseferi/SOLID