Skip to content

Commit 73b2ba9

Browse files
author
Dominik Liebler
committed
Merge remote-tracking branch 'memsb/master'
2 parents 22fc211 + 6edac3f commit 73b2ba9

File tree

9 files changed

+384
-0
lines changed

9 files changed

+384
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The patterns can be structured in roughly three different categories. Please cli
4141
* [Mediator](Mediator) [:notebook:](http://en.wikipedia.org/wiki/Mediator_pattern)
4242
* [NullObject](NullObject) [:notebook:](http://en.wikipedia.org/wiki/Null_Object_pattern)
4343
* [Observer](Observer) [:notebook:](http://en.wikipedia.org/wiki/Observer_pattern)
44+
* [Specification](Specification) [:notebook:](http://en.wikipedia.org/wiki/Specification_pattern)
4445
* [State](State) [:notebook:](http://en.wikipedia.org/wiki/State_pattern)
4546
* [Strategy](Strategy) [:notebook:](http://en.wikipedia.org/wiki/Strategy_pattern)
4647
* [TemplateMethod](TemplateMethod) [:notebook:](http://en.wikipedia.org/wiki/Template_method_pattern)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* An abstract specification allows the creation of wrapped specifications
6+
*/
7+
abstract class AbstractSpecification implements SpecificationInterface
8+
{
9+
/**
10+
* Checks if given item meets all criteria
11+
*
12+
* @param Item $item
13+
*
14+
* @return bool
15+
*/
16+
public function isSatisfiedBy(Item $item)
17+
{
18+
}
19+
20+
/**
21+
* Creates a new logical AND specification
22+
*
23+
* @param SpecificationInterface $spec
24+
*
25+
* @return SpecificationInterface
26+
*/
27+
public function plus(SpecificationInterface $spec)
28+
{
29+
return new Plus($this, $spec);
30+
}
31+
32+
/**
33+
* Creates a new logical OR composite specification
34+
*
35+
* @param SpecificationInterface $spec
36+
*
37+
* @return SpecificationInterface
38+
*/
39+
public function either(SpecificationInterface $spec)
40+
{
41+
return new Either($this, $spec);
42+
}
43+
44+
/**
45+
* Creates a new logical NOT specification
46+
*
47+
* @return SpecificationInterface
48+
*/
49+
public function not()
50+
{
51+
return new Not($this);
52+
}
53+
}

Specification/Either.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* A logical AND specification
6+
*/
7+
class Either extends AbstractSpecification
8+
{
9+
10+
protected $left;
11+
protected $right;
12+
13+
/**
14+
* A composite wrapper of two specifications
15+
*
16+
* @param SpecificationInterface $left
17+
* @param SpecificationInterface $right
18+
19+
*/
20+
public function __construct(SpecificationInterface $left, SpecificationInterface $right)
21+
{
22+
$this->left = $left;
23+
$this->right = $right;
24+
}
25+
26+
/**
27+
* Returns the evaluation of both wrapped specifications as a logical AND
28+
*
29+
* @param Item $item
30+
*
31+
* @return bool
32+
*/
33+
public function isSatisfiedBy(Item $item)
34+
{
35+
return $this->left->isSatisfiedBy($item) || $this->right->isSatisfiedBy($item);
36+
}
37+
}

Specification/Item.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* An trivial item
6+
*/
7+
class Item
8+
{
9+
protected $price;
10+
11+
/**
12+
* An item must have a price
13+
*
14+
* @param int $price
15+
16+
*/
17+
public function __construct($price)
18+
{
19+
$this->price = $price;
20+
}
21+
22+
/**
23+
* Get the items price
24+
*
25+
* @return int
26+
*/
27+
public function getPrice()
28+
{
29+
return $this->price;
30+
}
31+
}

Specification/Not.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* A logical Not specification
6+
*/
7+
class Not extends AbstractSpecification
8+
{
9+
10+
protected $spec;
11+
12+
/**
13+
* Creates a new specification wrapping another
14+
*
15+
* @param SpecificationInterface $spec
16+
17+
*/
18+
public function __construct(SpecificationInterface $spec)
19+
{
20+
$this->spec = $spec;
21+
}
22+
23+
/**
24+
* Returns the negated result of the wrapped specification
25+
*
26+
* @param Item $item
27+
*
28+
* @return bool
29+
*/
30+
public function isSatisfiedBy(Item $item)
31+
{
32+
return !$this->spec->isSatisfiedBy($item);
33+
}
34+
}

Specification/Plus.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* A logical AND specification
6+
*/
7+
class Plus extends AbstractSpecification
8+
{
9+
10+
protected $left;
11+
protected $right;
12+
13+
/**
14+
* Creation of a locical AND of two specifications
15+
*
16+
* @param SpecificationInterface $left
17+
* @param SpecificationInterface $right
18+
19+
*/
20+
public function __construct(SpecificationInterface $left, SpecificationInterface $right)
21+
{
22+
$this->left = $left;
23+
$this->right = $right;
24+
}
25+
26+
/**
27+
* Checks if the composite AND of specifications passes
28+
*
29+
* @param Item $item
30+
*
31+
* @return bool
32+
*/
33+
public function isSatisfiedBy(Item $item)
34+
{
35+
return $this->left->isSatisfiedBy($item) && $this->right->isSatisfiedBy($item);
36+
}
37+
}

Specification/PriceSpecification.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* A specification to check an Item is priced between min and max
6+
*/
7+
class PriceSpecification extends AbstractSpecification
8+
{
9+
protected $maxPrice;
10+
protected $minPrice;
11+
12+
/**
13+
* Sets the optional maximum price
14+
*
15+
* @param int $maxPrice
16+
*/
17+
public function setMaxPrice($maxPrice)
18+
{
19+
$this->maxPrice = $maxPrice;
20+
}
21+
22+
/**
23+
* Sets the optional minimum price
24+
*
25+
* @param int $minPrice
26+
*/
27+
public function setMinPrice($minPrice)
28+
{
29+
$this->minPrice = $minPrice;
30+
}
31+
32+
/**
33+
* Checks if Item price falls between bounds
34+
*
35+
* @param Item $item
36+
*
37+
* @return bool
38+
*/
39+
public function isSatisfiedBy(Item $item)
40+
{
41+
if ( !empty($this->maxPrice) && $item->getPrice() > $this->maxPrice) {
42+
return false;
43+
}
44+
if ( !empty($this->minPrice) && $item->getPrice() < $this->minPrice) {
45+
return false;
46+
}
47+
48+
return true;
49+
}
50+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
namespace DesignPatterns\Specification;
3+
4+
/**
5+
* An interface for a specification
6+
*/
7+
interface SpecificationInterface
8+
{
9+
/**
10+
* A boolean evaluation indicating if the object meets the specification
11+
*
12+
* @param Item $item
13+
*
14+
* @return bool
15+
*/
16+
public function isSatisfiedBy(Item $item);
17+
18+
/**
19+
* Creates a logical AND specification
20+
*
21+
* @param SpecificationInterface $spec
22+
23+
*/
24+
public function plus(SpecificationInterface $spec);
25+
26+
/**
27+
* Creates a logical OR specification
28+
*
29+
* @param SpecificationInterface $spec
30+
31+
*/
32+
public function either(SpecificationInterface $spec);
33+
34+
/**
35+
* Creates a logical not specification
36+
*/
37+
public function not();
38+
}

0 commit comments

Comments
 (0)