Избегайте выходных аргументов (не имеет побочных эффектов) - PullRequest
2 голосов
/ 18 января 2020

Я читаю «Чистый код» от Роберта C. Мы с Мартином не можем полностью понять разделы «Не иметь побочных эффектов» и «Выходные аргументы» на страницах с 44 по 45.

В разделе «Не иметь побочных эффектов» указано, что изменения передаются в параметры метода считаются побочными эффектами и не должны выполняться.

В разделе «Выходные аргументы» указано, что параметры метода не должны изменяться. Метод должен изменять состояние своего объекта-владельца только в том случае, если необходимо изменить какое-либо состояние.

Я понимаю, что побочные эффекты и выходные аргументы могут привести к запутанному поведению и ошибкам, если метод, который действительно определяет это поведение, вызывается клиентом, который не полностью осведомлен об этом. Кроме того, это проблематично c при работе в многопоточной среде.

Но, учитывая, что книга «Чистый код» написана на основе примеров с Java, я запутался.

Давайте рассмотрим пример. Давайте предположим, что у нас есть класс игрока:

public class Player {
    private int healthPoints;
    private boolean alive = true;

    public Player(int healthPoints) {
        if(healthPoints < 1) {
            throw new IllegalArgumentException();
        }
        this.healthPoints = healthPoints;
    }

    public boolean isAlive() {
        return this.alive;
    }

    public void fight(Player otherPlayer) {
        //do some fighting which will change this instance
        // but also the otherPlayer instance
    }
}

Если мы сейчас вызовем следующую функцию:

player1.fight(player2);

Это изменит статус player1, а также статус player2. Это не одобряется Робертом C. Мартин в большинстве случаев. Но на самом деле я вижу эту картину очень часто. Большинство Java программ, которые действительно имеют мутации и объекты, изменяются вне области, в которой они были созданы.

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

battle.fight(player1, player2)

Я что-то здесь пропускаю? Когда можно изменять параметры внутри метода (в Java)? Я задал довольно похожий вопрос: go ( Является ли изменение параметров объекта в методе (в Java) плохой практикой? ).

1 Ответ

1 голос
/ 18 января 2020

В конце концов, эти правила существуют, чтобы упростить жизнь программистам, исключив неожиданное поведение. Они помогают людям рассуждать о программах. Поэтому очень важно убедиться, что вы можете посмотреть на строку кода и понять, что она делает.

Если я как программист вижу строку:

player1.fight(player2);

Я бы ожидал, что и player1, и player2 будут видоизменены каким-либо образом. Это также относится к Arrays.sort(array);, который является частью языка.

Однако, если в вашей функции isAlive() вы выполнили некоторую мутацию (возможно, убивая игроков с нулевым здоровьем), что в моем По мнению, будет плохой практикой, поскольку я, как программист, ожидаю, что функция с именем isFoo() или getFoo() просто возвратит данные об объекте без каких-либо мутаций.

В В конце концов, эти рекомендации помогут вам упростить вашу жизнь, когда вы вернетесь и посмотрите на свой код через год, поэтому, если у вас есть сомнения, спросите себя, что вы ожидаете от метода с такой же сигнатурой? (то есть что я ожидаю от public void setAge(int age);? Это делает то, что я ожидаю?)

PS

Некоторые языки (например, Haskell) вообще не допускают никаких мутаций. Исключая IO и случайность, единственный способ, которым функция может влиять на программу, через ее возвращаемое значение. Стоит проверить, хотите ли вы узнать, как можно «программировать без побочных эффектов».

...