如果我们要解释规格模式,它将是;一个返回true 或false 的逻辑。复合规格类有一个标准方法,称为isSatisfiedBy ,它返回true 或false 的值。这是通过检查给定的对象,看它是否满足我们所设定的规格来完成的。
场景
你正在出售你的房子,并且有一些用户必须满足的标准,以便购买你的房子,该用户必须:
-
最低年龄为
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"
假设我们在应用程序的多个地方使用这段代码。如果有一天规则改变了,我们就有可能在反映变化的时候出现一些问题,比如浪费时间,犯错误等等。另外,它看起来已经不漂亮了,但如果我们不得不给它添加更多的检查,它甚至会看起来更难看。
在下面的例子中,我们将一次性实现 "硬编码规范 "和 "参数化规范"(你不需要这样做)。硬编码规范 "不需要任何参数传递给实际的规范类--即UserStillAliveSpecification 和UserIsAdultSpecification 。参数化规格 "确实需要向实际规格类传递参数--即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';