bentools/specification

提供 Specification Pattern 的实现。PHP7+

3.0.1 2018-04-17 15:29 UTC

This package is auto-updated.

Last update: 2024-09-15 00:06:59 UTC


README

Latest Stable Version License Build Status Coverage Status Scrutinizer Code Quality Total Downloads

bentools/specification

PHP7.1+ 对 Specification Pattern 的实现。

目标

Specification Pattern 允许你将一些条件结构封装成值对象。这在你平时的代码中可能没有意义,但当你的业务规则组合达到较高的圈复杂度时,它可能很有用。

因此,将你的条件封装到具有特定错误处理的命名对象中,可以帮助你

  • 向现有规则中添加新业务规则
  • 更好地理解你的条件结构
  • 找出哪些条件使其他条件无效
  • 避免难以阅读的“千层面”代码

Specification Pattern 的原则借鉴了领域驱动设计,但可以在任何地方应用。

概述

规范是一种增强的条件结构,可以与其他规范链接。

以下是创建规范的方法

require_once __DIR__ . '/vendor/autoload.php';

use function BenTools\Specification\spec;

$color = 'green';
$spec = spec('green' === $color);
$spec->validate(); // Hurray! Our specification has been validated.

如你所见,使用 validate() 方法来验证规范是否满足。它返回 void(无)。

当一个规范未满足时,validate() 方法会抛出 UnmetSpecificationException

use function BenTools\Specification\spec;

$color = 'green';
$size = 'small';
$spec = spec('green' === $color)->and('big' === $size);
$spec->validate(); // Oh no! An UnmetSpecificationException has been thrown.

处理这些异常时,你可以知道哪些规范失败了。为了识别它们,你可以给每个规范命名

use BenTools\Specification\Exception\UnmetSpecificationException;
use function BenTools\Specification\spec;

$color = 'green';
$size = 'small';

$spec = spec('green' === $color)->withLabel('Color specification')
            ->and('big' === $size)->withLabel('Size specification');
try {
    $spec->validate();
} catch (UnmetSpecificationException $e) {
    foreach ($e->getUnmetSpecifications() as $unmetSpecification) {
        if (null !== $unmetSpecification->getLabel()) {
            printf('%s failed.' . PHP_EOL, $unmetSpecification->getLabel());
        }
    }
}

// Outputs: Size specification failed.

规范快速检查

你不必处理 try/catch 块,可以通过调用 $spec->isSatisfied() 来检查规范是否满足,这将为你处理这些并返回一个布尔值。

use BenTools\Specification\Exception\UnmetSpecificationException;
use function BenTools\Specification\spec;

$color = 'green';
$size = 'small';

$spec = spec('green' === $color)->withLabel('Color specification')
            ->and('big' === $size)->withLabel('Size specification');
            
var_dump($spec->isSatisfied()); // (bool) false

创建规范

spec()group()not() 函数以及 and()or() 方法是规范工厂,它们将返回一个 Specification 对象。它们接受以下参数

  • 一个布尔值
  • 一个将解析为布尔值的可调用对象
  • 一个现有的 Specification 对象

示例

use function BenTools\Specification\spec;
use function BenTools\Specification\group;
use function BenTools\Specification\not;

spec(true); // Specification met
not(false); // Specification met
not(spec(function () {
    return false;
})); // Specification met
group(not(spec(false))->or(true)); // Specification met

分组和链式规范

一个 Specification 对象包含 andor 方法,可以用来创建复合规范。你也可以使用 group() 函数,它将像括号一样工作

use function BenTools\Specification\spec;
use function BenTools\Specification\group;
use function BenTools\Specification\not;

spec(true)
    ->and(
        group(
            spec(true)->or(false)
        )
        ->or(
            not(false)
        )
    ); // Specification met

创建你自己的规范

由于 Specification Pattern 的目的是测试你的业务规则,因此最好实现你自己的 Specification 类。

use BenTools\Specification\Exception\UnmetSpecificationException;
use BenTools\Specification\Specification;

class SpecProductInStock extends Specification
{
    /**
     * @var Product
     */
    private $product;

    /**
     * SpecProductInStock constructor.
     * @param Product $product
     */
    public function __construct(Product $product)
    {
        $this->product = $product;
        $this->label = sprintf('Product %s in stock verification', $product->getName());
    }

    /**
     * Validate the specification.
     * If the specification is unmet the implementation MUST throw an UnmetSpecificationException.
     *
     * @throws UnmetSpecificationException
     */
    public function validate(): void
    {
        if (false === $this->product->isInStock()) {
            throw new UnmetSpecificationException($this);
        }
    }
}

高级示例

由于 Specification Pattern 的目的是测试你的业务规则,因此你应该实现自己的 Specification 类。

查看我们的示例以开始。

安装

composer require bentools/specification ^3.0

许可证

MIT