Skip to content

Instantly share code, notes, and snippets.

@Ferror
Last active March 31, 2022 10:31
Show Gist options
  • Save Ferror/4bf4fbd0cd6848bc66841725bfae92f9 to your computer and use it in GitHub Desktop.
Save Ferror/4bf4fbd0cd6848bc66841725bfae92f9 to your computer and use it in GitHub Desktop.
Specification Tree vs Iterable approach
<?php
class AndSpecification extends Specification
{
public function __construct(
private SpecificationInterface $left,
private SpecificationInterface $right,
) {
}
public function isSatisfiedBy(object $candidate): bool
{
return $this->left->isSatisfiedBy($candidate) && $this->right->isSatisfiedBy($candidate);
}
}
<?php
class Guard
{
/**
* @param iterable<Specification> $requirements
*/
public function __construct(private iterable $requirements)
{
}
public function isSatisfiedByIterableApproach(OrderInterface $order): bool
{
// Iterable approach
foreach ($this->requirements as $requirement) {
if (!$requirement->isSatisfiedBy($order)) {
return false;
}
}
return true;
}
public function isSatisfiedByDynamicTreeApproach(OrderInterface $order): bool
{
// Dynamic Tree approach
$first = array_shift($this->requirements);
foreach ($this->requirements as $requirement) {
$first = $first->and($requirement);
}
return $first->isSatisfiedBy($order);
}
public function isSatisfiedByStaticApproach(OrderInterface $order): bool
{
// Static approach
$requirements = new RequiredNonEmptyCartSpecification();
$requirements
->and(new RequiredBillingAddressSpecification())
->and(new RequiredShippingSpecification())
->and(new RequiredPaymentSpecification())
;
return $requirements->isSatisfiedBy($order);
}
}
<?php
class OrSpecification extends Specification
{
public function __construct(
private SpecificationInterface $left,
private SpecificationInterface $right,
) {
}
public function isSatisfiedBy(object $candidate): bool
{
return $this->left->isSatisfiedBy($candidate) || $this->right->isSatisfiedBy($candidate);
}
}
<?php
abstract class Specification
{
public abstract function isSatisfiedBy(object $candidate): bool;
public function and(SpecificationInterface $specification): SpecificationInterface
{
return new AndSpecification($this, $specification);
}
public function or(SpecificationInterface $specification): SpecificationInterface
{
return new OrSpecification($this, $specification);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment