Answer the question
In order to leave comments, you need to log in
What is the best way to handle method parameters?
I had an argument with a colleague about class design.
There is a class for calculating the delivery of goods to a certain city by two delivery services: sdek and ems (to simplify, only two. There may be more).
The class has two dependencies, the sdek calculator and the ems calculator. How they work in this case is not important.
There is a public calculate method that takes two parameters: an array of goods and a city.
There are also several internal methods that are responsible for calculating specific services cdekCourier cdekPickup emsPickup.
Each of these methods requires the same products and city to calculate.
Dispute essence:
One considers that in each method (cdekCourier cdekPickup emsPickup) it is necessary to transfer parameters.
Another believes that it is better to write the goods and the city into properties, and then access them from these methods.
We cannot argue with each other.
The class itself in two versions is shown below.
The question is which option is better and why? Or are they both bad?
class DeliveryCalculator1
{
protected $cdekCalculator;
protected $emsCalculator;
public function __construct($cdekCalculator, $emsCalculator)
{
$this->cdekCalculator = $cdekCalculator;
$this->emsCalculator = $emsCalculator;
}
public function calculate($products, $city): array
{
$conditions = [];
if ($condition = $this->cdekCourier($products, $city)) {
$conditions[] = $condition;
}
if ($condition = $this->cdekPickup($products, $city)) {
$conditions[] = $condition;
}
if ($condition = $this->emsPickup($products, $city)) {
$conditions[] = $condition;
}
return $conditions;
}
protected function cdekCourier($products, $city): array
{
//тут ещё какая-то логика, которая определяет условия доставки, если она вообще возможна
$condition = $this->cdekCalculator->courier($products, $city);
return $condition ?: null;
}
protected function cdekPickup($products, $city): array
{
//тут ещё какая-то логика, которая определяет условия доставки, если она вообще возможна
$condition = $this->cdekCalculator->pickup($products, $city);
return $condition ?: null;
}
protected function emsPickup($products, $city): array
{
//тут ещё какая-то логика, которая определяет условия доставки, если она вообще возможна
$condition = $this->emsCalculator->pickup($products, $city);
return $condition ?: null;
}
}
class DeliveryCalculator2
{
protected $cdekCalculator;
protected $emsCalculator;
protected $products;
protected $city;
public function __construct($cdekCalculator, $emsCalculator)
{
$this->cdekCalculator = $cdekCalculator;
$this->emsCalculator = $emsCalculator;
}
public function calculate($products, $city): array
{
$this->products = $products;
$this->city = $city;
$conditions = [];
if ($condition = $this->cdekCourier()) {
$conditions[] = $condition;
}
if ($condition = $this->cdekPickup()) {
$conditions[] = $condition;
}
if ($condition = $this->emsPickup()) {
$conditions[] = $condition;
}
return $conditions;
}
protected function cdekCourier(): array
{
//тут еще какая-то логика, которая определяет условия доставки, если она вообще возможна
$condition = $this->cdekCalculator->courier($this->products, $this->city);
return $condition ?: null;
}
protected function cdekPickup(): array
{
//тут еще какая-то логика, которая определяет условия доставки, если она вообще возможна
$condition = $this->cdekCalculator->pickup($this->products, $this->city);
return $condition ?: null;
}
protected function emsPickup(): array
{
//тут еще какая-то логика, которая определяет условия доставки, если она вообще возможна
$condition = $this->emsCalculator->courier($this->products, $this->city);
return $condition ?: null;
}
}
Answer the question
In order to leave comments, you need to log in
It is quite simple to argue and even refer to specific paragraphs from the Implementing domain-driven design book, namely, what the author writes about services. The author of the book explains quite clearly why services should not have state.
You have a classic service and you have a problem, just because you basically approached the design of your service the wrong way.
First of all you need to design the interface CalculatorInterface
interface CalculatorInterface {
public function calculate($products, $city);
}
class CdekCalculator implements CalculatorInterface {
public function calculate($products, $city) {
// реализация расчета через cdek
}
}
class EmsCalculator implements CalculatorInterface {
public function calculate($products, $city) {
// реализация расчета через ems
}
}
class Delivery {
private $calculator;
public function __construct(CalculatorInterface $calculator) {
$this->calculator = $calculator;
}
public function calculate($products, $city) {
//тут ещё какая-то логика, которая определяет условия доставки, если она вообще возможна
return $this->calculator->calculate($products, $city);
}
}
Uncle Bob used to say "The best functions are those with no parameters!". So properties.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question