PHP中的规范设计模式实例

62 阅读1分钟

如果我们要解释规格模式,它将是;一个返回truefalse 的逻辑。复合规格类有一个标准方法,称为isSatisfiedBy ,它返回truefalse 的值。这是通过检查给定的对象,看它是否满足我们所设定的规格来完成的。

场景

你正在出售你的房子,并且有一些用户必须满足的标准,以便购买你的房子,该用户必须:

  • 最低年龄为18 (这是法律规定,不会改变)。

  • 口袋里有£500000.00 (这可以根据市场情况随时改变)。

  • 必须是alive (显然!)。

例子

用户类

class User
{
    private $age;
    private $amountOwned;
    private $isAlive;

    public function __construct(int $age, float $amountOwned, bool $isAlive)
    {
        $this->age = $age;
        $this->amountOwned = $amountOwned;
        $this->isAlive = $isAlive;
    }

    public function getAge(): int
    {
        return $this->age;
    }

    public function getAmountOwned(): float
    {
        return $this->amountOwned;
    }

    public function getIsAlive(): bool
    {
        return $this->isAlive;
    }
}

如果我们使用经典的函数式编程,我们的代码将看起来像下面这样:

$saleAmount = 500000.00;

$user = new User(29, 700000.00, true);

if (
    true === $user->getIsAlive() &&
    $user->getAge() >= 18 &&
    $user->getAmountOwned() >= $saleAmount
) {
    echo 'Can buy'.PHP_EOL;
} else {
    echo 'Cannot buy'.PHP_EOL;
}

// Result "Can buy"

假设我们在应用程序的多个地方使用这段代码。如果有一天规则改变了,我们就有可能在反映变化的时候出现一些问题,比如浪费时间,犯错误等等。另外,它看起来已经不漂亮了,但如果我们不得不给它添加更多的检查,它甚至会看起来更难看。

在下面的例子中,我们将一次性实现 "硬编码规范 "和 "参数化规范"(你不需要这样做)。硬编码规范 "不需要任何参数传递给实际的规范类--即UserStillAliveSpecificationUserIsAdultSpecification 。参数化规格 "确实需要向实际规格类传递参数--即UserHasEnoughMoneySpecification

interface SpecificationInterface
{
    public function isSatisfiedBy(User $user): bool;
}
class UserStillAliveSpecification implements SpecificationInterface
{
    public function isSatisfiedBy(User $user): bool
    {
        return $user->getIsAlive();
    }
}
class UserIsAdultSpecification implements SpecificationInterface
{
    private const MINIMUM_LEGAL_AGE_LIMIT = 18;

    public function isSatisfiedBy(User $user): bool
    {
        return $user->getAge() >= self::MINIMUM_LEGAL_AGE_LIMIT;
    }
}
class UserHasEnoughMoneySpecification implements SpecificationInterface
{
    private $saleAmount;

    public function __construct(float $saleAmount)
    {
        $this->saleAmount = $saleAmount;
    }

    public function isSatisfiedBy(User $user): bool
    {
        return $user->getAmountOwned() >= $this->saleAmount;
    }
}
class House
{
    private $specifications;

    public function add(SpecificationInterface $specification)
    {
        $this->specifications[] = $specification;

        return $this;
    }

    public function canBeSold(User $user): bool
    {
        /** @var SpecificationInterface $specification */
        foreach ($this->specifications as $specification) {
            if (!$specification->isSatisfiedBy($user)) {
                return false;
            }
        }

        return true;
    }
}
$saleAmount = 500000.00;

$user = new User(29, 700000.00, true);

$house = (new House())
    ->add(new UserStillAliveSpecification())
    ->add(new UserIsAdultSpecification())
    ->add(new UserHasEnoughMoneySpecification($saleAmount));

$result = $house->canBeSold($user);

echo true === $result ? 'Can Buy' : 'Cannot buy';