Categories
OOP

The SOLID principles of object-oriented design

SOLID is an acronym representing a set of five design principles to make software design more understandable, flexible, and maintainable. These principles were introduced by Robert C. Martin and are widely used in object-oriented programming. Let’s dive into these principles with explanations and examples using PHP:

1. Single Responsibility Principle (SRP)

  • Definition: A class should have only one reason to change, meaning it should have only one job or responsibility.
  • Concept: Encourage creating classes that have only one functionality.
// Violating SRP
class UserManager {
    public function createUser() {
        // code to create a user
    }

    public function logError($error) {
        // code to log error
    }
}

// Complying with SRP
class UserManager {
    public function createUser() {
        // code to create a user
    }
}

class Logger {
    public function logError($error) {
        // code to log error
    }
}

2. Open/Closed Principle (OCP)

  • Definition: Software entities should be open for extension but closed for modification.
  • Concept: You should be able to add new functionality without changing existing code.
// Violating OCP
class Rectangle {
    public $width;
    public $height;
}

class AreaCalculator {
    public function calculate($rectangle) {
        return $rectangle->width * $rectangle->height;
    }
}

// Complying with OCP
interface Shape {
    public function area();
}

class Rectangle implements Shape {
    public $width;
    public $height;

    public function area() {
        return $this->width * $this->height;
    }
}

class Circle implements Shape {
    public $radius;

    public function area() {
        return pi() * pow($this->radius, 2);
    }
}

class AreaCalculator {
    public function calculate(Shape $shape) {
        return $shape->area();
    }
}

3. Liskov Substitution Principle (LSP)

  • Definition: Subtypes must be substitutable for their base types without altering the correctness of the program.
  • Concept: Objects of a superclass should be replaceable with objects of a subclass without affecting the program’s correctness.
// Violating LSP
class Bird {
    public function fly() {
        // code for flying
    }
}

class Penguin extends Bird {
    public function fly() {
        // Penguins can’t fly!
        throw new Exception('Can’t fly');
    }
}

// Complying with LSP
interface Bird {
    public function move();
}

class Sparrow implements Bird {
    public function move() {
        // code for flying
    }
}

class Penguin implements Bird {
    public function move() {
        // code for walking
    }
}

4. Interface Segregation Principle (ISP)

  • Definition: Clients should not be forced to implement interfaces they do not use.
  • Concept: Instead of having a bloated interface, split it into smaller and more specific ones so that the clients will only have to know about the methods that are of interest to them.
// Violating ISP
interface Worker {
    public function work();
    public function eat();
}

class HumanWorker implements Worker {
    public function work() {
        // working
    }

    public function eat() {
        // eating
    }
}

// Complying with ISP
interface Workable {
    public function work();
}

interface Eatable {
    public function eat();
}

class HumanWorker implements Workable, Eatable {
    public function work() {
        // working
    }

    public function eat() {
        // eating
    }
}

5. Dependency Inversion Principle (DIP)

  • Definition: Depend on abstractions, not on concretions.
  • Concept: High-level modules should not depend on low-level modules but should depend on abstractions. Also, abstractions should not depend on details. Details should depend on abstractions.
// Violating DIP
class LightBulb {}

class Switch {
    private $bulb;

    public function operate(LightBulb $bulb) {
        $this->bulb = $bulb;
        // operate the light bulb
    }
}

// Complying with DIP
interface Switchable {
    public function operate();
}

class LightBulb implements Switchable {
    public function operate() {
        // turn on/off the light bulb
    }
}

class Switch {
    private $device;

    public function operate(Switchable $device) {
        $this->device = $device;
        $this->device->operate();
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *