Le design pattern Specification

Les spécifications d'une application ne sont pas forcément sur papier. Elles peuvent être aussi décrites par du code.

Jérémy 🤘
Jérémy 🤘

Les spécifications d'une application ne sont pas forcément sur papier. Elles peuvent être aussi décrites par du code. C'est justement ce que nous allons voir avec le design pattern Specification.

Construire une spécification claire pour un besoin métier où les objets peuvent être vérifiés est le principe de base de ce pattern.

Une classe de spéficication est une interface que vous allez devoir implémenter et qui ne contiendra qu'une seule méthode isSatisfiedBy et qui va retourner un boolean afin d'indiquer si oui ou non l'objet satisfait la spéficiation.

Prenons un exemple simple d'une spécification qui nous dit que le prix d'un produit doit être compris dans une certaine tranche de prix.

  • SpecificationInterface.php
Copier
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\Specification;

interface SpecificationInterface
{
    /** @param mixed $object */
    public function isSatisfiedBy($object): bool;
}
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\Specification;

interface SpecificationInterface
{
    /** @param mixed $object */
    public function isSatisfiedBy($object): bool;
}
  • PriceSpecification.php
Copier
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\Specification;

class PriceSpecification implements Specification
{
    protected float $maxPrice;
    protected float $minPrice;

    public function __construct(float $minPrice = 0, float $maxPrice = 0)
    {
        if ($maxPrice < $minPrice) {
            throw new \LogicException("Maximum price cannot be smaller than minimum price.");
        }
        
        $this->minPrice = $minPrice;
        $this->maxPrice = $maxPrice;
    }

    public function isSatisfiedBy($product): bool
    {
        return $product->getPrice() >= $this->minPrice
            && $product->getPrice() <= $this->maxPrice
        ;
    }
}
<?php

declare(strict_types=1);

namespace DesignPatterns\Behavioral\Specification;

class PriceSpecification implements Specification
{
    protected float $maxPrice;
    protected float $minPrice;

    public function __construct(float $minPrice = 0, float $maxPrice = 0)
    {
        if ($maxPrice < $minPrice) {
            throw new \LogicException("Maximum price cannot be smaller than minimum price.");
        }
        
        $this->minPrice = $minPrice;
        $this->maxPrice = $maxPrice;
    }

    public function isSatisfiedBy($product): bool
    {
        return $product->getPrice() >= $this->minPrice
            && $product->getPrice() <= $this->maxPrice
        ;
    }
}
  • foo.php
Copier
<?php

declare(strict_types=1);

use DesignPatterns\Behavioral\Specification\PriceSpecification;

$product = new Product();
$product->setPrice(100);

$priceSpecification = new PriceSpecification(10, 50);
$result = $priceSpecification->isSatisfiedBy($product);

// $result => false
<?php

declare(strict_types=1);

use DesignPatterns\Behavioral\Specification\PriceSpecification;

$product = new Product();
$product->setPrice(100);

$priceSpecification = new PriceSpecification(10, 50);
$result = $priceSpecification->isSatisfiedBy($product);

// $result => false

Source