Полиморфизм и внедрение зависимостей - слишком много зависимостей

Итак, я прочитал, что если мы видим оператор switch, это признак того, что ему нужен полиморфизм.

Я видел такой пример полиморфизма:

include 'vendor/autoload.php';

$calc = new Calculator();

$calc->setOperands(5, 6);
$calc->setOperation(new Addition);
echo $result = $calc->calculate();

И, конечно, могут быть различные классы, такие как Subtract, Multiply, Root и т. Д.

Теперь допустим, что я хочу использовать этот код в фреймворке Laravel, но это, я думаю, должно применяться к любой фреймворке php.

Пример класса сложения (так же может работать любая другая функция калькулятора)

Class Addition implements Operation {
    public function run($num, $current){
        return $current + $num;
    }

}

Калькулятор:

Class Calculator {

    protected $result = 0;
    protected $operands = array();
    protected $operation;

    public function getResult()
    {
        return $this->result;
    }

    public function setOperands()
    {
        $this->operands = func_get_args();
    }

    public function setOperation(Operation $operation)
    {
        $this->operation = $operation;
    }

    public function calculate()
    {
        foreach ($this->operands as $num) {
            echo $num;
            if ( ! is_numeric($num)) {
                throw new InvalidArgumentException;
            }
            $this->result = $this->operation->run($num, $this->result);
        }

        return $this->result;
    }




}

Я пишу такой класс:

class CalcUser
{
  private $calc; 

  public function __construct(Calculator $calc)
  {
    $this->calc = $calc;
  }

  public function index()
  {
    $this->calc->setOperands(5, 6);
    $this->calc->setOperation(new Addition);
    $result = $calc->calculate();

    // imagine we have long formula to calculate so we add here many functions
    // (5+6) * 12 + 21  / 6 + sqrt(4) ...
    $this->calc->setOperands($result, 6);
    $this->calc->setOperation(new AnyOtherFunction);
    echo $result = $calc->calculate();

  }

}

И это должно работать, не проверял мой класс CalcUser, просто написал прямо здесь.

Но я вижу одну проблему - там используется ключевое слово new

А также то, что я прочитал, это:

Признаки непроверяемого кода:

  1. Новые операторы

Единственный раз, когда допустимо создавать экземпляр класса внутри другого класса, это когда этот объект является тем, что мы называем объектом-значением, или простым контейнером с геттерами и сеттерами, который не выполняет никакой реальной работы.

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

Но тогда есть еще одна вещь:

Слишком много зависимостей

Если вы обнаружите, что конкретному классу требуется четыре или более зависимостей, это чаще всего признак того, что ваш класс требует слишком много

Таким образом, легко получить более 3-х зависимостей, используя только один калькулятор с множеством различных функций.

Так как же мне переформатировать код, чтобы избежать слишком большого количества зависимостей?

1 ответ

Существует множество различных представлений по этому вопросу (когда класс зависит от чего-либо), но зависимости класса обычно рассматриваются как то, что передается в конструктор, то есть то, что необходимо для создания экземпляра класса как объекта. Поэтому, когда у вас есть экземпляр вашего калькулятора, вызывающий метод и передающий другой объект - в этом случае реализация Operation - в методе нет прямой зависимости.

Так что в основном ваш Calculator класс не имеет зависимостей, ваш CalcUser имеет одну зависимость (Calculator).

Кроме того, я думаю, что вещь о new -keyword/construct заключается в том, что класс не должен вызывать что-либо сам по себе, передавая через него зависимость метода. Это может быть признаком того, что вновь созданный объект является избыточным, если он используется только в экосистеме этого класса. Скажи, что ты никогда не используешь Operation где-нибудь еще в классе, который зависит от него, то есть в этом случае:

class Calculator
{

    ...

    public function newSumOperation()
    {
        $this->setOperands(func_get_args());
        $this->setOperation(new Addition);
    }

   ...
}

class CalcUser
{
    ... 
    public function index()
    {
        $this->calc->newSumOperation(1,2,3);
        $result = $this->calc->calculate();

        // imagine we have long formula to calculate so we add here many functions
        // (5+6) * 12 + 21  / 6 + sqrt(4) ...
        $this->newXXXXXOperation(4,3,2);
        echo $result = $calc->calculate();

    }

}

Итак, как вы видите, в приведенном выше примере вы никогда не используете Addition вне Calculator-учебный класс. Если вы думаете о реальном калькуляторе, вы вводите числа и получаете результат; и между этим калькулятор не продвигает логику сложения чисел вместе с чем-то другим, потому что калькулятор выполняет сложение.

Другие вопросы по тегам