Skip to main content

1_Design Patterns in Software Engineering

Design Pattern In Software Engineering

Design pattern in software develop are general, reusable solutions to the most acurring problem in designing software design.
What are those problems?

While designing of the system to face the scenarios where you have to decide which approach or method  use to solve the problem.
1) Problem can be the structure of the system.
2) The flow of the data in the system.
3) The interaction between different modules in the same system.

While developing the system you came to face with different problem. Now you have a developer team. You assign this task to these developer individually and every develop solve the problem according to its approach.
Now question is which approach/solution is efficient rest of others.

Now after analysis you decide If certain problem you face in developing software, solve it with that particular solution.

Example

If you want, at loading of the application you want to create single object and access each module/class data using this single object than you have to use Singleton Design Pattern.

There are different categories in design pattern.
1) Creational Design Pattern
These design patterns deals with creation of object.

2) Structural Design Pattern
These design pattern deals with structuring of the developing software.

3) Behavioral Design Pattern

These design pattern focus on the interaction of different object in the same system.

Creational Design Pattern

1) Singleton Design pattern:
Singleton design pattern is a creational design pattern that ensure the class have only single instance throughout the life cycle of the application. This instance must have all access of the application processes.

Key Characteristics

1) Private constructor of the class so that directly object can't be created.
2) When constructor will become private you can't create object with new keyword.
3) Now you will create object using class static method and you know the static method can be called directly with class name.
3) Store object in the private static variable.
4) Method adopt to create singleton object is Lazy initialization. The object is created on the tie of it needed.

Benefit: Lazy initialization save memory and you create object when it needed.

1) Object creation with lazy initialization code example

<?php
class Database {
    // Hold the class instance
    private static $instance = null;
    private $connection;

    // DB configuration
    private $host = 'localhost';
    private $dbname = 'test_db';
    private $username = 'root';
    private $password = '';

    // Private constructor to prevent multiple instances
    private function __construct() {
        $this->connection = new PDO(
            "mysql:host=$this->host;dbname=$this->dbname",
            $this->username,
            $this->password
        );
        $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }

    // Prevent cloning the instance
    private function __clone() { }

    // Get the instance (create if it doesn't exist)
    public static function getInstance() {
        if (!self::$instance) {
            self::$instance = new Database();
        }
        return self::$instance;
    }

    // Get the database connection
    public function getConnection() {
        return $this->connection;
    }
}

    //Usage

    $db = Database::getInstance();
    $conn = $db->getConnection();

    $stmt = $conn->query("SELECT * FROM users");
    $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

    print_r($users);

?>

2) Eager Initialization
In eager initialization the instance created on class loading.

Code example

<?php

class Database {
    private static $instance = new Database(); // instance created immediately
    private function __construct() { /* ... */ }

    public static function getInstance() {
        return self::$instance;
    }
}

?>


Why store instance on static property?

Static variable is required to hold the instance at class level, not at object level. Same instance will return on every getInstance() (static) method call.

What happened if our application running in the multi-Thread Environment?
Here is the problem came, when our application run in the multi-thread environment. On each thread app run individually than if we go for object creation in lazy Initialization than getInstance() method called will be twice depend how much application instance are running and each app run on single thread individually.
When the method call many times the instance will be created.
That means Standard Lazy Singleton is not thread  Safe.

Let understand it with php approch.
In Concurrent Environment, multiple PHP process runinng like web request, jobs, crons using singleton memory. Now the problem is the memory singleton object is occupied
1) is not shareable.
2) Each process have its own memory.

So race condition can accure where multiple processes start inserting record in DB. Making duplication data (Data integrity no more).

Race condition problem can prevent at database level using Locking and Atomic Insert

In Laravel

1. User::updateOrInsert

2. User::firstOrCreate

In MYSQLi/MariaDB Database Queres

<?php
$email = 'user@example.com';
$name = 'Test User';

$sql = "INSERT INTO users (email, name) VALUES (:email, :name)
        ON DUPLICATE KEY UPDATE name = VALUES(name)";
$stmt = $pdo->prepare($sql);
$stmt->execute(['email' => $email, 'name' => $name]);
?>

In PDO example

This Lock the row (or table) during check + insert

<?php
try {
    $pdo->beginTransaction();

    // Lock the row or table
    $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email FOR UPDATE");
    $stmt->execute(['email' => $email]);
    $user = $stmt->fetch();

    if (!$user) {
        // Safe to insert now
        $insert = $pdo->prepare("INSERT INTO users (email, name) VALUES (:email, :name)");
        $insert->execute(['email' => $email, 'name' => $name]);
    }

    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}

?>

Standard php:  It is singleton Safe one request = one thread.

Multi-thread Php Environment (Swoole, RoadRunner, ReactPHP, pthreads): You must handle synchronization using locks.
Use lock mechanism to handle instance creation. how this technique work. lets say after locking the method or code block, only one thread will access this at a time and rest thread will wait. If first thread create the instance than second thread will get the instances is already created so he will use the instance.

Thread-Safe Singleton in PHP with Mutex (for Swoole or Pthreads)

<?php
class Database {
    private static $instance = null;
    private static $lock;
    private $connection;

    private function __construct() {
        $this->connection = new PDO(/* your DSN */);
    }

    public static function getInstance() {
        // Create lock if not exists
        if (self::$lock === null) {
            self::$lock = new \Swoole\Lock(SWOOLE_MUTEX);
        }

        // Double-checked locking
        if (self::$instance === null) {
            self::$lock->lock(); // Lock before critical section

            if (self::$instance === null) {
                self::$instance = new Database();
            }

            self::$lock->unlock(); // Unlock after instance created
        }

        return self::$instance;
    }

    public function getConnection() {
        return $this->connection;
    }
}


?>

Can we break singleton design pattern ?

We can use Reflection Api (RA) to break singleton design.

Real world example where singleton is highly use.

1) Establish DB connection (PDO, mysqli).

Prevent to create new connection on every query execution.

$db = Database::getInstance()->getConnection();

<?php
$db = Database::getInstance()->getConnection();
?>

2) Content Logging inside the project.

make a central class of Logging and whenever you want to log some content inside the file, just call it and 

<?php
Logger::getInstance()->log('This is log');
?>


3) App Configuration and Environment Manager.

In framework configuration reading and from file or DB
Instead of reading/loading every time. Load sigle time at the start of the application

<?php
$config = Config::getInstance();
$apiKey = $config->get("api_key");
?>

4) Cache Manager

For performance optimized systems: heavy searching/e-commerse.
Prevent connection establish over an over again in redis, memcache connections.

Get the data from cache using single time created instance.

<?php
$cache = CacheManager::getInstance()->get('products');
?>

5) Dispatch Event
In laravel application we having many services register in app registery. we can run these service as an event where-ever we need, we just call the dispatcher to dispatch the service event.

<?php
EventDispatcher::getInstance()->dispatch('user.registered', $user);
?>

Can we break singleton design pattern ?

We can use Reflection Api (RA) to break singleton design. W cannot create instance of the class singleton class after locking the instance creation code.
In java we can break the Singleton pattern and access the private constructor as well. instantiate multiple objects.
How we acheive reflection?

We get the instance of the class in main function in java. it return the function if already created than create and return.
now we have instance  s1
Singleton s1 = Singleton.getInstance();

Now get scope of the private constructor

Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();

After that constructor.setAccessible(true) // Bypass private constructor


 Singleton s2 = constructor.newInstance(); // New instance created

 System.out.println("s1 hash: " + s1.hashCode());

 System.out.println("s2 hash: " + s2.hashCode());

How we can acheive this in php

In php we can achieve this but it is not strictly enforce like in java. Php doesn't have built in reflection api but still we can acheive this to break reflection/break the behavior of sigleton. By pass the private constructor and create multiple instances. 

<?php
class Singleton {
    private static $instance;

    private function __construct() {
        // Optional: Prevent reflection here (manually)
        if (self::$instance !== null) {
            throw new \Exception("Use getInstance() instead of creating via constructor.");
        }
    }

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

    private function __clone() {}
    private function __wakeup() {}
}

?>


<?php
$instance1 = Singleton::getInstance();

$reflection = new ReflectionClass('Singleton');
$constructor = $reflection->getConstructor();
$constructor->setAccessible(true);

$instance2 = $reflection->newInstanceWithoutConstructor();

echo spl_object_hash($instance1) . PHP_EOL;
echo spl_object_hash($instance2) . PHP_EOL;

?>

Output

000000007f97b1b40000000062527e25

000000007f97b1b50000000062527e25


Note:

ReflectionClass, which is a built-in class in PHP, and yes — its methods like getConstructor(), setAccessible(true), and newInstanceWithoutConstructor() are also built-in methods.







Comments

Popular posts from this blog

Install MariaDB Latest Version 11.4 in Red Hat Version 9

 This this post i will show you step by step the installation process of mariaDB in red hat version 9. Step1 Run the command to pull the latest updated packages on applications installed in your system. -dnf update If you get Kernal update than reboot the system -reboot Step2 Go to official mariaDB site Make mariadb repository in /etc/yum.repos.d Place the configuration in this file # MariaDB 11.4 RedHatEnterpriseLinux repository list - created 2024-09-24 11:12 UTC # https://mariadb.org/download/ [mariadb] name = MariaDB # rpm.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details. # baseurl = https://rpm.mariadb.org/11.4/rhel/$releasever/$basearch baseurl = https://mirrors.aliyun.com/mariadb/yum/11.4/rhel/$releasever/$basearch # gpgkey = https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB gpgkey = https://mirrors.aliyun.com/mariadb/yum/RPM-GPG-KEY-MariaDB gpgcheck = 1 Now install the mariaDB with its dependencies package...

Linux Commands

  Linux Commands 1.  OS-Release -cat /etc/os-release -cat /etc/redhat-release show os //kernal information -uname  show kernal middleware It is intermediator between hardware and software. -uname  -r what is process architect. -uname -p To show all information -uname -a 2.  Date-CAL -date -cal 3.  Booting in Linux (Run-Levels) Shutdown/Close pc -init 0  Single user mode -init 1 Multiple user mode -init 2 Multiple user mode with network plus full support Not use -init 4 Graphical mode init 5 Reboot the system -init 6 4.  Target command in Linux (systemctl) With the help of target we can manage system specific as well as user specific task. Target command is system Control (systemctl). Basically it is utility, which build to replace 'init' command. What systemctl can do ?  We can find its all commands with the help of single command. write systemctl enter twice TAB button. //it will list all its commands. Show current system mode - systemctl...