Задать вопрос
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;
	}
}

  • Вопрос задан
  • 595 просмотров
Подписаться 3 Простой 6 комментариев
Пригласить эксперта
Ответы на вопрос 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!". Так что свойства.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы