Skip to content

willavelar/php-design-pattern-behavioral-observer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Command

Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing.


When an order is generated, we need to perform several actions such as storing it in the database, sending it by email, and generating a log.

The problem

If we need to add more actions after generating order, our function will grow infinitely.

<?php
class Order
{
    public string $customerName;
    public \DateTimeInterface $finalizationDate;
    public Budget $budget;
}
<?php
class Budget 
{
    public float $value;
    public int $items;
}
<?php
class GenerateOrder
{
    private float $budgetValue;
    private int $items;
    private string $customereName;

    public function __construct(float $budgetValue, int $items, string $customereName)
    {
        $this->budgetValue = $budgetValue;
        $this->items = $items;
        $this->customereName = $customereName;
    }

    public function getBudgetValue(): float
    {
        return $this->budgetValue;
    }

    public function getItems(): int
    {
        return $this->items;
    }

    public function getCustomereName(): string
    {
        return $this->customereName;
    }

}
<?php
class GenerateOrderHandler
{
    public function execute(GenerateOrder $generateOrder)
    {
        $budget =  new Budget();

        $budget->items = $generateOrder->getItems();
        $budget->value = $generateOrder->getBudgetValue();

        $order = new Order();
        $order->finalizationDate = new \DateTimeImmutable();
        $order->customerName = $generateOrder->getCustomereName();
        $order->budget = $budget;

        new CreateOrderDatabase($order);
        new GenerateOrderLog($order);
        new SendOrderEmail($order);
    }
}
<?php
class CreateOrderDatabase
{
    public function __construct(Order $order)
    {
        echo "create new order in database" . PHP_EOL;
    }
}
class GenerateOrderLog
{
    public function __construct(Order $order)
    {
        echo "generate order creation log" . PHP_EOL;
    }
}
<?php
class SendOrderEmail
{
    public function __construct(Order $order)
    {
        echo "send email to customer" . PHP_EOL;
    }
}

The solution

Now, using the Observer design patern, we can step outside the class as many actions as we want, without changing it.

<?php
interface ActionsAfterGenerateOrder
{
    public function execAction(Order $order) : void;
}
<?php
class CreateOrderDatabase implements ActionsAfterGenerateOrder
{
    public function execAction(Order $order): void
    {
        echo "create new order in database" . PHP_EOL;
    }
}
<?php
class GenerateOrderLog implements ActionsAfterGenerateOrder
{
    public function execAction(Order $order): void
    {
        echo "generate order creation log" . PHP_EOL;
    }
}
<?php
class SendOrderEmail implements ActionsAfterGenerateOrder
{
    public function execAction(Order $order): void
    {
        echo "send email to customer" . PHP_EOL;
    }
}
<?php
class GenerateOrderHandler
{
    /** @var ActionsAfterGenerateOrder[]  */
    private array $actionsAfterGenerateOrder = [];

    public function addActionsAfterGenerateOrder(ActionsAfterGenerateOrder $action)
    {
        $this->actionsAfterGenerateOrder[] = $action;
    }
    public function execute(GenerateOrder $generateOrder)
    {
        $budget =  new Budget();

        $budget->items = $generateOrder->getItems();
        $budget->value = $generateOrder->getBudgetValue();

        $order = new Order();
        $order->finalizationDate = new \DateTimeImmutable();
        $order->customerName = $generateOrder->getCustomereName();
        $order->budget = $budget;

        foreach ($this->actionsAfterGenerateOrder as $action) {
            $action->execAction($order);
        }
    }
}

Installation for test

PHP Version Support Composer Version Support

composer install
php wrong/test.php {budgetValue} {items} {customereName}
php right/test.php {budgetValue} {items} {customereName}

About

a simple php example about the behavioral pattern: Observer

Topics

Resources

Stars

Watchers

Forks

Languages