/solid-principle

solid principle of object oriented design

solid-principle

SOLID is an acronym that represents a set of principles for writing maintainable and scalable software. These principles were first introduced by Robert C. Martin (also known as Uncle Bob) in his 2000 paper, "Design Principles and Design Patterns." Here is a brief explanation of each of the SOLID principles:

  1. Single Responsibility Principle (SRP)
  2. Open-Closed Principle (OCP)
  3. Liskov Substitution Principle (LSP)
  4. Interface Segregation Principle (ISP)
  5. Dependency Inversion Principle (DIP)

By following these principles, developers can write software that is easier to maintain, extend, and test. The SOLID principles are widely used in object-oriented programming, and they form the foundation for many design patterns and best practices.

Single resposilibity

Single Responsibility Principle (SRP) is a design principle in object-oriented programming that states that a class should have only one reason to change, i.e., it should have only one responsibility or job.

In practical terms, this means that a class should be responsible for one thing and one thing only, and that it should not have multiple responsibilities or concerns. This helps to keep classes focused, maintainable, and flexible, and to avoid complex dependencies and coupling between different parts of the code.

Here is a PHP example of a class that violates the Single Responsibility Principle:

class User {
  public function register() {
    // Register the user
  }

  public function login() {
    // Log in the user
  }

  public function sendEmail() {
    // Send an email to the user
  }

  public function getProfile() {
    // Get the user's profile
  }
}

In this example, the User class has multiple responsibilities: registering users, logging them in, sending them emails, and retrieving their profiles. This violates the SRP, as each of these responsibilities should be handled by a separate class.

A better approach would be to split the responsibilities into separate classes, like this:

class UserRegistration {
  public function register() {
    // Register the user
  }
}

class UserLogin {
  public function login() {
    // Log in the user
  }
}

class UserEmail {
  public function sendEmail() {
    // Send an email to the user
  }
}

class UserProfile {
  public function getProfile() {
    // Get the user's profile
  }
}

Open/Closed principle

the Open/Closed Principle (OCP) is a design principle in object-oriented programming that states that a class or module should be open for extension but closed for modification. In other words, you should be able to extend the behavior of a class without modifying its source code.

Here is a PHP example of a class that violates the Open/Closed Principle:

class PaymentProcessor {
  public function pay($amount, $paymentMethod) {
    if ($paymentMethod == 'credit_card') {
      // Process credit card payment
    } else if ($paymentMethod == 'paypal') {
      // Process PayPal payment
    } else if ($paymentMethod == 'bitcoin') {
      // Process Bitcoin payment
    } else {
      throw new Exception('Invalid payment method');
    }
  }
}

In this example, the PaymentProcessor class has a pay method that accepts an amount and a payment method as parameters. The method then checks the payment method and processes the payment accordingly. However, if a new payment method is added, the class would need to be modified to handle it, which violates the OCP.

A better approach would be to create a separate class for each payment method, and to make them implement a common interface, like this:

interface PaymentMethod {
  public function processPayment($amount);
}

class CreditCardPayment implements PaymentMethod {
  public function processPayment($amount) {
    // Process credit card payment
  }
}

class PayPalPayment implements PaymentMethod {
  public function processPayment($amount) {
    // Process PayPal payment
  }
}

class BitcoinPayment implements PaymentMethod {
  public function processPayment($amount) {
    // Process Bitcoin payment
  }
}

class PaymentProcessor {
  public function pay($amount, PaymentMethod $paymentMethod) {
    $paymentMethod->processPayment($amount);
  }
}

This way, the PaymentProcessor class is open for extension, as new payment methods can be added by creating new classes that implement the PaymentMethod interface, without modifying the PaymentProcessor class. This promotes better code organization, reduces coupling, and makes the code more flexible and maintainable.

Liskov substitution

The Liskov Substitution Principle (LSP) is one of the SOLID principles that states that objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program. In other words, a subclass should be able to be used in place of its parent class without any unexpected behavior.

example: php

<?php

interface Shape {
  public function area();
}

class Rectangle implements Shape {
  protected $width;
  protected $height;
  
  public function setWidth($width) {
    $this->width = $width;
  }
  
  public function setHeight($height) {
    $this->height = $height;
  }
  
  public function area() {
    return $this->width * $this->height;
  }
}

class Square implements Shape {
  protected $side;
  
  public function setSide($side) {
    $this->side = $side;
  }
  
  public function area() {
    return $this->side * $this->side;
  }
}

function printArea(Shape $shape) {
  echo "The area is: " . $shape->area() . "\n";
}

$rectangle = new Rectangle();
$rectangle->setWidth(5);
$rectangle->setHeight(10);
printArea($rectangle); // Output: The area is: 50

$square = new Square();
$square->setSide(5);
printArea($square); // Output: The area is: 25

In this example, the Rectangle and Square classes implement the Shape interface, which has a area() method. The printArea() function takes a Shape object as a parameter and calls its area() method to calculate and print the area. Both Rectangle and Square classes can be used interchangeably with the Shape interface, demonstrating the Liskov Substitution Principle.

Interface Segragation

Interface Segregation Principle (ISP) is a design principle in object-oriented programming that states that a class should not be forced to implement interfaces it does not use. In other words, it is better to have several small and focused interfaces rather than a single large and generic interface.

interface Machine {
  public function print();
  public function scan();
  public function fax();
}

class AllInOnePrinter implements Machine {
  public function print() {
    // Print the document
  }

  public function scan() {
    // Scan the document
  }

  public function fax() {
    // Fax the document
  }
}

split the interface

interface Printer {
  public function print();
}

interface Scanner {
  public function scan();
}

interface Fax {
  public function fax();
}

class AllInOnePrinter implements Printer, Scanner {
  public function print() {
    // Print the document
  }

  public function scan() {
    // Scan the document
  }
}

Dependency Inversion

The Dependency Inversion Principle (DIP) is a design principle in object-oriented programming that states that high-level modules should not depend on low-level modules, but both should depend on abstractions. In other words, a module should depend on an abstract interface, rather than on a concrete implementation.

Here is a PHP example of a class that violates the Dependency Inversion Principle:

class MySQLConnection
{
    public function connect()
    {
        // handle the database connection
        return 'Database connection';
    }
}

class User
{
    private $dbConnection;

    public function __construct(MySQLConnection $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }
}
interface DBConnectionInterface
{
    public function connect();
}

class MySQLConnection implements DBConnectionInterface
{
    public function connect()
    {
        // handle the database connection
        return 'Database connection';
    }
}

class User
{
    private $dbConnection;

    public function __construct(DBConnectionInterface $dbConnection)
    {
        $this->dbConnection = $dbConnection;
    }
}

code smell

~ bad practise

In software development, "code smell" refers to any symptom in the source code of a program that suggests there may be a deeper problem or issue with the design or implementation. It is a term used to describe code that is hard to understand, modify, or maintain.

Code smells are not necessarily bugs, but they are warning signs that the code may be difficult to work with or prone to defects. Examples of code smells include duplicated code, overly complex functions, long parameter lists, inconsistent naming conventions, and overly nested conditional statements.

Identifying code smells is important because they can be early indicators of more serious problems that may require significant refactoring or redesign. By addressing code smells early in the development process, developers can improve the quality, maintainability, and performance of their code.

Resources