mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-07-31 20:20:15 +02:00
PHP7 Specification
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* An abstract specification allows the creation of wrapped specifications.
|
||||
*/
|
||||
abstract class AbstractSpecification implements SpecificationInterface
|
||||
{
|
||||
/**
|
||||
* Checks if given item meets all criteria.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isSatisfiedBy(Item $item);
|
||||
|
||||
/**
|
||||
* Creates a new logical AND specification.
|
||||
*
|
||||
* @param SpecificationInterface $spec
|
||||
*
|
||||
* @return SpecificationInterface
|
||||
*/
|
||||
public function plus(SpecificationInterface $spec)
|
||||
{
|
||||
return new Plus($this, $spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new logical OR composite specification.
|
||||
*
|
||||
* @param SpecificationInterface $spec
|
||||
*
|
||||
* @return SpecificationInterface
|
||||
*/
|
||||
public function either(SpecificationInterface $spec)
|
||||
{
|
||||
return new Either($this, $spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new logical NOT specification.
|
||||
*
|
||||
* @return SpecificationInterface
|
||||
*/
|
||||
public function not()
|
||||
{
|
||||
return new Not($this);
|
||||
}
|
||||
}
|
30
Behavioral/Specification/AndSpecification.php
Normal file
30
Behavioral/Specification/AndSpecification.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
class AndSpecification implements SpecificationInterface
|
||||
{
|
||||
/**
|
||||
* @var SpecificationInterface[]
|
||||
*/
|
||||
private $specifications;
|
||||
|
||||
/**
|
||||
* @param SpecificationInterface[] ...$specifications
|
||||
*/
|
||||
public function __construct(SpecificationInterface ...$specifications)
|
||||
{
|
||||
$this->specifications = $specifications;
|
||||
}
|
||||
|
||||
public function isSatisfiedBy(Item $item): bool
|
||||
{
|
||||
$satisfied = [];
|
||||
|
||||
foreach ($this->specifications as $specification) {
|
||||
$satisfied[] = $specification->isSatisfiedBy($item);
|
||||
}
|
||||
|
||||
return !in_array(false, $satisfied);
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* A logical OR specification.
|
||||
*/
|
||||
class Either extends AbstractSpecification
|
||||
{
|
||||
protected $left;
|
||||
protected $right;
|
||||
|
||||
/**
|
||||
* A composite wrapper of two specifications.
|
||||
*
|
||||
* @param SpecificationInterface $left
|
||||
* @param SpecificationInterface $right
|
||||
*/
|
||||
public function __construct(SpecificationInterface $left, SpecificationInterface $right)
|
||||
{
|
||||
$this->left = $left;
|
||||
$this->right = $right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evaluation of both wrapped specifications as a logical OR.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSatisfiedBy(Item $item)
|
||||
{
|
||||
return $this->left->isSatisfiedBy($item) || $this->right->isSatisfiedBy($item);
|
||||
}
|
||||
}
|
@@ -2,29 +2,19 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* An trivial item.
|
||||
*/
|
||||
class Item
|
||||
{
|
||||
protected $price;
|
||||
|
||||
/**
|
||||
* An item must have a price.
|
||||
*
|
||||
* @param int $price
|
||||
* @var float
|
||||
*/
|
||||
public function __construct($price)
|
||||
private $price;
|
||||
|
||||
public function __construct(float $price)
|
||||
{
|
||||
$this->price = $price;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the items price.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPrice()
|
||||
public function getPrice(): float
|
||||
{
|
||||
return $this->price;
|
||||
}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* A logical Not specification.
|
||||
*/
|
||||
class Not extends AbstractSpecification
|
||||
{
|
||||
protected $spec;
|
||||
|
||||
/**
|
||||
* Creates a new specification wrapping another.
|
||||
*
|
||||
* @param SpecificationInterface $spec
|
||||
*/
|
||||
public function __construct(SpecificationInterface $spec)
|
||||
{
|
||||
$this->spec = $spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the negated result of the wrapped specification.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSatisfiedBy(Item $item)
|
||||
{
|
||||
return !$this->spec->isSatisfiedBy($item);
|
||||
}
|
||||
}
|
21
Behavioral/Specification/NotSpecification.php
Normal file
21
Behavioral/Specification/NotSpecification.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
class NotSpecification implements SpecificationInterface
|
||||
{
|
||||
/**
|
||||
* @var SpecificationInterface
|
||||
*/
|
||||
private $specification;
|
||||
|
||||
public function __construct(SpecificationInterface $specification)
|
||||
{
|
||||
$this->specification = $specification;
|
||||
}
|
||||
|
||||
public function isSatisfiedBy(Item $item): bool
|
||||
{
|
||||
return !$this->specification->isSatisfiedBy($item);
|
||||
}
|
||||
}
|
30
Behavioral/Specification/OrSpecification.php
Normal file
30
Behavioral/Specification/OrSpecification.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
class OrSpecification implements SpecificationInterface
|
||||
{
|
||||
/**
|
||||
* @var SpecificationInterface[]
|
||||
*/
|
||||
private $specifications;
|
||||
|
||||
/**
|
||||
* @param SpecificationInterface[] ...$specifications
|
||||
*/
|
||||
public function __construct(SpecificationInterface ...$specifications)
|
||||
{
|
||||
$this->specifications = $specifications;
|
||||
}
|
||||
|
||||
public function isSatisfiedBy(Item $item): bool
|
||||
{
|
||||
$satisfied = [];
|
||||
|
||||
foreach ($this->specifications as $specification) {
|
||||
$satisfied[] = $specification->isSatisfiedBy($item);
|
||||
}
|
||||
|
||||
return in_array(true, $satisfied);
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* A logical AND specification.
|
||||
*/
|
||||
class Plus extends AbstractSpecification
|
||||
{
|
||||
protected $left;
|
||||
protected $right;
|
||||
|
||||
/**
|
||||
* Creation of a logical AND of two specifications.
|
||||
*
|
||||
* @param SpecificationInterface $left
|
||||
* @param SpecificationInterface $right
|
||||
*/
|
||||
public function __construct(SpecificationInterface $left, SpecificationInterface $right)
|
||||
{
|
||||
$this->left = $left;
|
||||
$this->right = $right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the composite AND of specifications passes.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSatisfiedBy(Item $item)
|
||||
{
|
||||
return $this->left->isSatisfiedBy($item) && $this->right->isSatisfiedBy($item);
|
||||
}
|
||||
}
|
@@ -2,47 +2,35 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* A specification to check an Item is priced between min and max.
|
||||
*/
|
||||
class PriceSpecification extends AbstractSpecification
|
||||
class PriceSpecification implements SpecificationInterface
|
||||
{
|
||||
protected $maxPrice;
|
||||
protected $minPrice;
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
private $maxPrice;
|
||||
|
||||
/**
|
||||
* Sets the optional maximum price.
|
||||
*
|
||||
* @param int $maxPrice
|
||||
* @var float|null
|
||||
*/
|
||||
public function setMaxPrice($maxPrice)
|
||||
private $minPrice;
|
||||
|
||||
/**
|
||||
* @param float $minPrice
|
||||
* @param float $maxPrice
|
||||
*/
|
||||
public function __construct($minPrice, $maxPrice)
|
||||
{
|
||||
$this->minPrice = $minPrice;
|
||||
$this->maxPrice = $maxPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional minimum price.
|
||||
*
|
||||
* @param int $minPrice
|
||||
*/
|
||||
public function setMinPrice($minPrice)
|
||||
public function isSatisfiedBy(Item $item): bool
|
||||
{
|
||||
$this->minPrice = $minPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if Item price falls between bounds.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSatisfiedBy(Item $item)
|
||||
{
|
||||
if (!empty($this->maxPrice) && $item->getPrice() > $this->maxPrice) {
|
||||
if ($this->maxPrice !== null && $item->getPrice() > $this->maxPrice) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($this->minPrice) && $item->getPrice() < $this->minPrice) {
|
||||
|
||||
if ($this->minPrice !== null && $item->getPrice() < $this->minPrice) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -38,15 +38,9 @@ SpecificationInterface.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
AbstractSpecification.php
|
||||
OrSpecification.php
|
||||
|
||||
.. literalinclude:: AbstractSpecification.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
Either.php
|
||||
|
||||
.. literalinclude:: Either.php
|
||||
.. literalinclude:: OrSpecification.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
@@ -56,15 +50,15 @@ PriceSpecification.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
Plus.php
|
||||
AndSpecification.php
|
||||
|
||||
.. literalinclude:: Plus.php
|
||||
.. literalinclude:: AndSpecification.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
Not.php
|
||||
NotSpecification.php
|
||||
|
||||
.. literalinclude:: Not.php
|
||||
.. literalinclude:: NotSpecification.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
|
@@ -2,36 +2,7 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Specification;
|
||||
|
||||
/**
|
||||
* An interface for a specification.
|
||||
*/
|
||||
interface SpecificationInterface
|
||||
{
|
||||
/**
|
||||
* A boolean evaluation indicating if the object meets the specification.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSatisfiedBy(Item $item);
|
||||
|
||||
/**
|
||||
* Creates a logical AND specification.
|
||||
*
|
||||
* @param SpecificationInterface $spec
|
||||
*/
|
||||
public function plus(SpecificationInterface $spec);
|
||||
|
||||
/**
|
||||
* Creates a logical OR specification.
|
||||
*
|
||||
* @param SpecificationInterface $spec
|
||||
*/
|
||||
public function either(SpecificationInterface $spec);
|
||||
|
||||
/**
|
||||
* Creates a logical not specification.
|
||||
*/
|
||||
public function not();
|
||||
public function isSatisfiedBy(Item $item): bool;
|
||||
}
|
||||
|
@@ -3,101 +3,44 @@
|
||||
namespace DesignPatterns\Behavioral\Specification\Tests;
|
||||
|
||||
use DesignPatterns\Behavioral\Specification\Item;
|
||||
use DesignPatterns\Behavioral\Specification\NotSpecification;
|
||||
use DesignPatterns\Behavioral\Specification\OrSpecification;
|
||||
use DesignPatterns\Behavioral\Specification\AndSpecification;
|
||||
use DesignPatterns\Behavioral\Specification\PriceSpecification;
|
||||
|
||||
/**
|
||||
* SpecificationTest tests the specification pattern.
|
||||
*/
|
||||
class SpecificationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSimpleSpecification()
|
||||
public function testCanOr()
|
||||
{
|
||||
$item = new Item(100);
|
||||
$spec = new PriceSpecification();
|
||||
$spec1 = new PriceSpecification(50, 99);
|
||||
$spec2 = new PriceSpecification(101, 200);
|
||||
|
||||
$this->assertTrue($spec->isSatisfiedBy($item));
|
||||
$orSpec = new OrSpecification($spec1, $spec2);
|
||||
|
||||
$spec->setMaxPrice(50);
|
||||
$this->assertFalse($spec->isSatisfiedBy($item));
|
||||
|
||||
$spec->setMaxPrice(150);
|
||||
$this->assertTrue($spec->isSatisfiedBy($item));
|
||||
|
||||
$spec->setMinPrice(101);
|
||||
$this->assertFalse($spec->isSatisfiedBy($item));
|
||||
|
||||
$spec->setMinPrice(100);
|
||||
$this->assertTrue($spec->isSatisfiedBy($item));
|
||||
$this->assertFalse($orSpec->isSatisfiedBy(new Item(100)));
|
||||
$this->assertTrue($orSpec->isSatisfiedBy(new Item(51)));
|
||||
$this->assertTrue($orSpec->isSatisfiedBy(new Item(150)));
|
||||
}
|
||||
|
||||
public function testNotSpecification()
|
||||
public function testCanAnd()
|
||||
{
|
||||
$item = new Item(100);
|
||||
$spec = new PriceSpecification();
|
||||
$not = $spec->not();
|
||||
$spec1 = new PriceSpecification(50, 100);
|
||||
$spec2 = new PriceSpecification(80, 200);
|
||||
|
||||
$this->assertFalse($not->isSatisfiedBy($item));
|
||||
$orSpec = new AndSpecification($spec1, $spec2);
|
||||
|
||||
$spec->setMaxPrice(50);
|
||||
$this->assertTrue($not->isSatisfiedBy($item));
|
||||
|
||||
$spec->setMaxPrice(150);
|
||||
$this->assertFalse($not->isSatisfiedBy($item));
|
||||
|
||||
$spec->setMinPrice(101);
|
||||
$this->assertTrue($not->isSatisfiedBy($item));
|
||||
|
||||
$spec->setMinPrice(100);
|
||||
$this->assertFalse($not->isSatisfiedBy($item));
|
||||
$this->assertFalse($orSpec->isSatisfiedBy(new Item(150)));
|
||||
$this->assertFalse($orSpec->isSatisfiedBy(new Item(1)));
|
||||
$this->assertFalse($orSpec->isSatisfiedBy(new Item(51)));
|
||||
$this->assertTrue($orSpec->isSatisfiedBy(new Item(100)));
|
||||
}
|
||||
|
||||
public function testPlusSpecification()
|
||||
public function testCanNot()
|
||||
{
|
||||
$spec1 = new PriceSpecification();
|
||||
$spec2 = new PriceSpecification();
|
||||
$plus = $spec1->plus($spec2);
|
||||
$spec1 = new PriceSpecification(50, 100);
|
||||
$orSpec = new NotSpecification($spec1);
|
||||
|
||||
$item = new Item(100);
|
||||
|
||||
$this->assertTrue($plus->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(150);
|
||||
$spec2->setMinPrice(50);
|
||||
$this->assertTrue($plus->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(150);
|
||||
$spec2->setMinPrice(101);
|
||||
$this->assertFalse($plus->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(99);
|
||||
$spec2->setMinPrice(50);
|
||||
$this->assertFalse($plus->isSatisfiedBy($item));
|
||||
}
|
||||
|
||||
public function testEitherSpecification()
|
||||
{
|
||||
$spec1 = new PriceSpecification();
|
||||
$spec2 = new PriceSpecification();
|
||||
$either = $spec1->either($spec2);
|
||||
|
||||
$item = new Item(100);
|
||||
|
||||
$this->assertTrue($either->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(150);
|
||||
$spec2->setMaxPrice(150);
|
||||
$this->assertTrue($either->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(150);
|
||||
$spec2->setMaxPrice(0);
|
||||
$this->assertTrue($either->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(0);
|
||||
$spec2->setMaxPrice(150);
|
||||
$this->assertTrue($either->isSatisfiedBy($item));
|
||||
|
||||
$spec1->setMaxPrice(99);
|
||||
$spec2->setMaxPrice(99);
|
||||
$this->assertFalse($either->isSatisfiedBy($item));
|
||||
$this->assertTrue($orSpec->isSatisfiedBy(new Item(150)));
|
||||
$this->assertFalse($orSpec->isSatisfiedBy(new Item(50)));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user