New_Horizons
@New_Horizons
Бред:

Как лучше обращаться с параметрами метода?

С коллегой возник спор на тему проектирования классов.

Есть класс для расчёта доставки товаров в определённый город двумя службами доставки: сдэк и емс (для упрощения только две. Их может быть больше).

у класса есть две зависимости, калькулятор сдэка и калькулятор емс. Как они работают в данном случае не важно.

Есть публичный метод calculate, который принимает два параметра: массив товаров и город.

Так же есть несколько внутренних методов, которые отвечают за расчёт по конкретным службам cdekCourier cdekPickup emsPickup.
Каждому из этих методов требуются для расчёта те же товары и город.

Суть спора:
Один считает, что в каждый метод (cdekCourier cdekPickup emsPickup) нужно передавать параметры.
Другой считает, что товары и город лушче записать в свойства, а потом обращаться к ним из этих методов.

Аргументировать друг другу свой вариант не можем.

Сам класс в двух вариантах приведён ниже.

Вопрос, какой вариант лучше и почему? Или может они оба плохи?)

Вариант 1

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;
	}
}

Вариант 2

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;
	}
}

  • Вопрос задан
  • 594 просмотра
Пригласить эксперта
Ответы на вопрос 2
@xfg
Аргументировать довольно просто и даже сослаться на конкретные абзацы из книги Implementing domain-driven design, а именно, то что автор пишет про сервисы. Автор книги довольно четко рассказывает почему сервисы не должны обладать состоянием.

У вас классический сервис и у вас проблема, только лишь потому, что вы впринципе неправильно подошли к проектированию вашего сервиса.

В первую очередь вам нужно спроектировать интерфейс CalculatorInterface

interface CalculatorInterface {
  public function calculate($products, $city);
}


Далее вам нужно создать две реализации этого интерфейса CdekCalculator и EmsCalculator

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);
  }
}


Предмета спора больше нет. Вы просто передаете в класс Delivery нужную реализацию калькулятора. Код выше это псевдоязык, не php и вообще только базовая идея того, как это должно быть. У вас наверняка тут же возникнет вопрос, как вам тогда выводить все расчеты доставки в ваш UI. Но извините не могу написать за вас всё приложение.

Это базовые вещи в объектно-ориентированном программировании. Называется полиморфизм подтипов. Без этих знаний невозможно писать хороший объектно-ориентированный код. Лучше оба придите к выводу, что вам срочно нужно почитать какие-нибудь книги об объектно-ориентированном программировании и начать с самых основ, что такое полиморфизм и в частности полиморфизм подтипов.

Вообще protected/private методы и ветвления из условных конструкций - это практически всегда показатель спагетти-кода и первый звоночек, что вы пишете процедурный код используя ООП синтаксис. Вы придете к этому выводу если будете разрабатывать через TDD, а затем сможете нагуглить ваши предположения у других программистов.
Ответ написан
kshnkvn
@kshnkvn
yay ✌️ t.me/kshnkvn
Дядя Боб говорил "The best functions are those with no parameters!". Так что свойства.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы