01/09/2017 - PHP
Classlar genişletmeye açık ama değiştirmeye kapalı olmalıdırlar.
# VIOLATION
class DiscountCalculator
{
public function calculate(string $itemType, float $itemPrice, int $unitTotal): float
{
$discount = 0;
if ($itemType == 'bread') {
$discount = $this->getDiscount(0.2, $itemPrice, $unitTotal); # 20%
} elseif ($itemType == 'rice') {
$discount = $this->getDiscount(0.4, $itemPrice, $unitTotal); # 40%
}
return $discount;
}
private function getDiscount(float $discount, float $itemPrice, int $unitTotal): float
{
return ($itemPrice * $unitTotal) * $discount;
}
}
$discountCalculator = new DiscountCalculator();
echo $discountCalculator->calculate('bread', 1.00, 5);
echo $discountCalculator->calculate('rice', 3.00, 4);
Yukarıda gördüğümüz gibi, DiscountCalculator
classı pek genişletmeye açıkmış gibi görünmüyor. Yeni tipler eklemeyi hayal edersek, bu class daha fazla değiştirmeye açıkmış gibi görünüyor. Bu durum da prensip ihlaline yol açıyor.
# REFACTORED
interface ItemInterface
{
public function setDiscountValue(float $discountValue);
public function getDiscountValue(): float;
}
class Bread implements ItemInterface
{
private $discountValue;
public function setDiscountValue(float $discountValue)
{
$this->discountValue = $discountValue;
}
public function getDiscountValue(): float
{
return $this->discountValue;
}
}
class Rice implements ItemInterface
{
private $discountValue;
public function setDiscountValue(float $discountValue)
{
$this->discountValue = $discountValue;
}
public function getDiscountValue(): float
{
return $this->discountValue;
}
}
class DiscountCalculator
{
public function calculate(ItemInterface $item, float $itemPrice, int $unitTotal): float
{
return ($itemPrice * $unitTotal) * $item->getDiscountValue();
}
}
$discountCalculator = new DiscountCalculator();
$bread = new Bread();
$bread->setDiscountValue(0.2);
$rice = new Rice();
$rice->setDiscountValue(0.4);
echo $discountCalculator->calculate($bread, 1.00, 5);
echo $discountCalculator->calculate($rice, 3.00, 4);
Yukarıda gördüğümüz gibi, elimizde Bread
ve Rice
classları var. Ayrıca DiscountCalculator
tam bir hesap yapma classı halini almış durumda. Eğer ileride yeni maddelerin hesaplamasını yapmak istersek, tek yapmamız gereken Bread
veya Rice
classlarına benzeyen bir class yaratıp, onu DiscountCalculator
classına enjekte etmek olacaktır. Sonuç olarak hiçbir yerde değişiklik yapmaya gerek olmayacaktır.