Table of Contents

  1. Singleton Pattern
  2. Factory Pattern
  3. Observer Pattern
  4. Strategy Pattern
  5. Conclusion

Singleton Pattern

The Singleton Pattern ensures that a class has only one instance and provides a global access point to that instance. This pattern is particularly useful for managing shared resources, such as database connections.

Implementation Example

class Database {
    private static $instance = null;

    private function __construct() {
        // Private constructor to prevent instantiation
    }

    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new Database();
        }
        return self::$instance;
    }

    public function connect() {
        // Connection logic here
        echo "Database connected!";
    }
}

// Usage
$db1 = Database::getInstance();
$db1->connect();

$db2 = Database::getInstance();
var_dump($db1 === $db2); // true, both are the same instance

Factory Pattern

The Factory Pattern provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. This is useful when the exact type of the object to be created is not known until runtime.

Implementation Example

interface Shape {
    public function draw();
}

class Circle implements Shape {
    public function draw() {
        return "Drawing a Circle";
    }
}

class Square implements Shape {
    public function draw() {
        return "Drawing a Square";
    }
}

class ShapeFactory {
    public static function createShape($type) {
        switch ($type) {
            case 'circle':
                return new Circle();
            case 'square':
                return new Square();
            default:
                throw new Exception("Shape not recognized.");
        }
    }
}

// Usage
$circle = ShapeFactory::createShape('circle');
echo $circle->draw(); // Drawing a Circle

$square = ShapeFactory::createShape('square');
echo $square->draw(); // Drawing a Square

Observer Pattern

The Observer Pattern defines a one-to-many dependency between objects, so that when one object changes state, all its dependents are notified and updated automatically. This pattern is useful for implementing event-driven systems.

Implementation Example

interface Observer {
    public function update($data);
}

class ConcreteObserver implements Observer {
    private $name;

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

    public function update($data) {
        echo "{$this->name} received update: {$data}\n";
    }
}

class Subject {
    private $observers = [];

    public function attach(Observer $observer) {
        $this->observers[] = $observer;
    }

    public function notify($data) {
        foreach ($this->observers as $observer) {
            $observer->update($data);
        }
    }
}

// Usage
$subject = new Subject();
$observer1 = new ConcreteObserver("Observer 1");
$observer2 = new ConcreteObserver("Observer 2");

$subject->attach($observer1);
$subject->attach($observer2);

$subject->notify("New Data Available!"); 
// Observer 1 received update: New Data Available!
// Observer 2 received update: New Data Available!

Strategy Pattern

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. This pattern lets the algorithm vary independently from clients that use it, making it easier to switch between different algorithms.

Implementation Example

interface PaymentStrategy {
    public function pay($amount);
}

class CreditCardPayment implements PaymentStrategy {
    public function pay($amount) {
        echo "Paid {$amount} using Credit Card.\n";
    }
}

class PayPalPayment implements PaymentStrategy {
    public function pay($amount) {
        echo "Paid {$amount} using PayPal.\n";
    }
}

class ShoppingCart {
    private $paymentStrategy;

    public function setPaymentStrategy(PaymentStrategy $strategy) {
        $this->paymentStrategy = $strategy;
    }

    public function checkout($amount) {
        $this->paymentStrategy->pay($amount);
    }
}

// Usage
$cart = new ShoppingCart();

$cart->setPaymentStrategy(new CreditCardPayment());
$cart->checkout(100); // Paid 100 using Credit Card.

$cart->setPaymentStrategy(new PayPalPayment());
$cart->checkout(200); // Paid 200 using PayPal.

Conclusion

Implementing design patterns in your PHP applications can greatly enhance the structure and maintainability of your code. By utilizing patterns like Singleton, Factory, Observer, and Strategy, you can create robust software architectures that are easier to manage and extend.


Learn more with useful resources