15/01/2019 - PHP
Specifications modelini açıklamak istersek, şöyle olur; true
veya false
döndüren bir mantık. Kompozit specification classı, true
veya false
değerleri döndüren isSatisfiedBy
adında standart bir methoda sahiptir. Bu, tarafımızdan belirlenen kriterleri karşılayıp karşılamadığını görmek için verilen nesneyi kontrol ederek yapılır.
Evinizi satıyorsunuz ve kullanıcının evinizi satın alabilmesi için bazı kriterleri yerine getirmesi gerekir. Kullanıcı:
18
yaşında olması gerekli (bu kanuni ve değişmeyecek olan bir kriterdir)£500000.00
ile gelmeli (bu piyasaya göre değişebilir)alive
olması gerekir (malumen!)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;
}
}
Klasik bir işlevsel programlama tekniği kullanıyor olsaydık, kodumuz aşağıdaki gibi olurdu.
$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"
Uygulamamızın birçok yerinde bu kod parçasını kullandığımızı varsayalım. Kriterler bir gün değişirse, değişiklikleri yansıtırken potansiyel olarak zaman kaybetme, hata yapma gibi bazı sorunlar ortaya çıkabilir. Ayrıca zaten hoş görünmüyor ancak daha fazla kriter eklemek zorunda kalırsak, daha çirkin bir hal alacağıda malum.
Aşağıdaki örnekte, bir kerede hem "sabit kodlanmış specifications" hem de "parametreli hale getirilmiş specifications" yöntemlerini uygulayacağız (yapmak zorunda değilsiniz). "Sabit kodlu specifications", gerçek specifications classına geçirilen herhangi bir argümana ihtiyaç duymaz - örneğin, UserStillAliveSpecification
ve UserIsAdultSpecification
. "Parametreli hale getirilmiş specifications", gerçek specifications classına geçirilen argüman veya argümanlara ihtiyaç duyar - örneğin, 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';