Есть исходный(старый) класс, который использует IF-ELSE простыню(ад)
/**
* Class DeliveryCalculatorOld
* old style
*/
class DeliveryCalculatorOld
{
public function cost(Order $order, string $type): float
{
if ($type === 'courier') {
return 300 + $order->weight * 10;
} elseif ($type === 'pickup') {
return 0;
} elseif ($type === 'post') {
return 150 + $order->weight * 5;
}
throw new \InvalidArgumentException("Unknown type: $type");
}
}Необходимо улучшить: "добавить: express, drone" + "заложить расширяемость"
Проведу рефакторинг + заложить новый стиль с OOP + DRY + ACID + SOLID
/**
* Class Order
* Zero boiler, safe, immutable
*/
class Order
{
public function __construct(
public readonly float $weight,
// You can add other typical order data here later:
// public readonly int $id,
// public readonly string $status,
) {}
}
interface DeliveryCostCalculatorInterface
{
public function calculate(Order $order): float;
}class CourierDeliveryCalculator implements DeliveryCostCalculatorInterface
{
public function calculate(Order $order): float
{
return (float)(300 + $order->weight * 10);
}
}
class PickupDeliveryCalculator implements DeliveryCostCalculatorInterface
{
public function calculate(Order $order): float
{
return (float)(0);
}
}
class PostDeliveryCalculator implements DeliveryCostCalculatorInterface
{
public function calculate(Order $order): float
{
return (float)(150 + $order->weight * 5);
}
}
// 2+ express, drone
/**
* Class ExpressDeliveryCalculator
*/
class ExpressDeliveryCalculator implements DeliveryCostCalculatorInterface
{
public function calculate(Order $order): float
{
return (float)(123 + $order->weight * 50);
}
}
/**
* Class DroneDeliveryCalculator
*/
class DroneDeliveryCalculator implements DeliveryCostCalculatorInterface
{
public function calculate(Order $order): float
{
return (float)(10 + $order->weight * 2);
}
}/**
* Class DeliveryCalculatorFactory
*/
class DeliveryCalculatorFactory
{
/**
* @todo update processing to CamelCase from snake_case | kebab-case (not only flat)
* @param string $type
* @return \DeliveryCostCalculatorInterface
*/
public function __invoke(string $type): DeliveryCostCalculatorInterface
{
$className = ucfirst(strtolower($type)) . 'DeliveryCalculator';
// $className = "App\\Services\\" . ucfirst(strtolower($type)) . 'DeliveryCalculator';
if (!class_exists($className)) {
throw new \InvalidArgumentException("Unknown type: $type (Class $className not found)");
}
if (!is_subclass_of($className, DeliveryCostCalculatorInterface::class)) {
throw new \UnexpectedValueException("Class $className must implement DeliveryCostCalculatorInterface");
}
return new $className();
}
}/**
* Class DeliveryCalculator
*/
class DeliveryCalculator
{
/**
* Dynamically loads the specific class and runs calculate()
* @param \Order $order
* @param string $type
* @return float
*/
public function cost(Order $order, string $type): float
{
$factory = new DeliveryCalculatorFactory();
return ($factory)($type)->calculate($order);
}
}
// run(test):
echo "\n".(new DeliveryCalculator())->cost(new Order(21.5), 'drone'); // 53
echo "\n".(new DeliveryCalculator())->cost(new Order(1.5), 'express'); // 198
echo "\n".(new DeliveryCalculator())->cost(new Order(82.5), 'post'); // 562.5
echo "\n".(new DeliveryCalculator())->cost(new Order(23.5), 'pickup'); // 0
echo "\n".(new DeliveryCalculator())->cost(new Order(0.15), 'courier'); // 301.5
// Uncaught InvalidArgumentException: Unknown type: nonexist (Class NonexistDeliveryCalculator not found)
//echo "\n".(new DeliveryCalculator())->cost(new Order(6.65), 'nonexist'); // 301.5
echo "\n --=:END:=-- \n";