Статьи

Практический рефакторинг PHP: метод удаления настроек

Установщик для определенного поля присутствует: возможно, это сгенерированный метод или используется для внедрения зависимостей.

Однако в текущем состоянии кода нет вариантов его использования [больше]: это либо метод, который никогда не вызывался, либо метод, вызываемый только во время построения.

Метод Remove Установка рефакторинга делает вас выбросить этот метод и формально сохранить неизменность объекта. Вы знаете, что не следует ожидать изменения состояния объекта, только когда у него нет методов, присваивающих его приватным полям (кроме конструктора).

Зачем удалять сеттер?

Если метод не служит какой-либо цели, желательно отбросить его, чтобы упростить дизайн (независимо от того, насколько он прост). Это верно для любого метода, но в случае с установщиком мы можем захотеть переложить его ответственность на другие методы, чтобы избавиться от очень общего фрагмента API, позволяя любому, имеющему ссылку на объект, связываться с внутреннее состояние.

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

Например, применяя дальнейшую технику рефакторинга, вы будете пользоваться большей свободой, поскольку вам нужно будет только проверять вызовы внутри класса, а не исследовать всю кодовую базу с помощью grep .

Объекты часто используются как неизменяемые: удаляя установщик, вы заставляете эту неизменность (по крайней мере, для этого поля). Класс, в котором вы удалили все сеттеры и методы изменения состояния, создают неизменяемые объекты.

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

меры

  1. Проверьте вызовы к установщику: он должен вызываться только внутри конструктора или никогда не вызываться вообще. Цель — сделать поле неизменным: обязательным условием является никогда не вызываемый сеттер.
  2. Если в фазе построения есть вызов , измените код для прямого доступа к полю.
  3. Если установщик вызывается сразу после new () , переместите значение в качестве параметра конструктора. Этот шаг охватывает использование сеттеров для внедрения зависимостей.
  4. Удалить метод настройки.

Тестовый набор должен пройти все время, не ломаясь.

пример

Объект предъявителя Вопроса должен отображаться в качестве заголовка вопроса, например, для использования в ссылке или элементе списка. Сеттер вызывается во время построения, чтобы убедиться, что текст правильно обрезан (конечные пробелы выбрасываются).

<?php
class RemoveSettingMethod extends PHPUnit_Framework_TestCase
{
    public function testAQuestionIsDisplayedTogetherWithTheNumberOfResponses()
    {
        $question = new Question('How do I install PHP on the washing machine?', 10);
        $this->assertEquals('How do I install PHP on the washing machine? (responses: 10)', $question->__toString());
    }
}

class Question
{
    private $text;
    private $responses;

    public function __construct($text, $responses = 0)
    {
        $this->setText($text);
        $this->responses = $responses;
    }

    public function setText($text)
    {
        $text = trim($text);
        $this->text = $text;
    }

    public function __toString()
    {
        return $this->text . ' (responses: ' . $this->responses . ')';
    }
}

Однако мы замечаем, что это просто объект, созданный для рендеринга, а не доменный; нам никогда не придется менять его текст (мы просто создадим новый объект). Метод setText () предоставляет возможность, которая нам не нужна и не нужна: давайте устраняем ее, начиная с тех мест, где он вызывается.

class Question
{
    private $text;
    private $responses;

    public function __construct($text, $responses = 0)
    {
        $text = trim($text);
        $this->text = $text;
        $this->responses = $responses;
    }

    public function setText($text)
    {
        $text = trim($text);
        $this->text = $text;
    }

    public function __toString()
    {
        return $this->text . ' (responses: ' . $this->responses . ')';
    }
}

Теперь сеттер больше не вызывается. Мы можем удалить это вообще.

class Question
{
    private $text;
    private $responses;

    public function __construct($text, $responses = 0)
    {
        $text = trim($text);
        $this->text = $text;
        $this->responses = $responses;
    }

    public function __toString()
    {
        return $this->text . ' (responses: ' . $this->responses . ')';
    }
}

Объект теперь формально неизменен и может передаваться везде, не беспокоясь о псевдонимах и о том, что будет делать с ним клиентский код. Класс также имеет меньше методов для поддержки.