The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:
Временная связь возникает между последовательными вызовами методов, когда они должны происходить в определенном порядке. Это неизбежно в императивном программировании, но мы можем уменьшить негативный эффект, просто превратив эти статические процедуры в функции. Взгляните на этот пример.
class Foo {
public List<String> names() {
List<String> list = new LinkedList();
Foo.append(list, "Jeff");
Foo.append(list, "Walter");
return list;
}
private static void append(
List<String> list, String item) {
list.add(item.toLowerCase());
}
}
Что вы об этом думаете? Я считаю, что понятно, что делает функция names()
— она создает список имен. Чтобы избежать дублирования, существует вспомогательная процедура append()
, которая преобразует элемент в нижний регистр и добавляет его в список.
Это плохой дизайн.
Это процедурный дизайн, и между строками метода names()
существует временная связь.
Давайте сначала покажу вам лучший (хотя не самый лучший!) дизайн, а затем я постараюсь объяснить его преимущества:
Идеальное решение для метода with()
создало бы новый экземпляр List
, заполнило бы его с помощью addAll(list)
, затем добавило бы элемент с помощью add(item)
и, наконец, возвратило бы его. Это было бы идеально неизменяемым, но медленным.
Итак, что не так с этим:
Выглядит абсолютно чисто, не так ли? Создайте список, добавьте в него два элемента и верните его. Да, сейчас он чистый - на данный момент. Потому что мы помним, что делает append()
. Через несколько месяцев, когда мы вернемся к этому коду, он будет выглядеть так:
Теперь понятно, что append()
фактически добавляет "Jeff"
в list
? Что произойдет, если я удалю эту строку? Это повлияет на возвращаемый результат в последней строке? Я не знаю. Мне нужно проверить тело метода append()
, чтобы убедиться.
Как насчет сначала возвращать list
и затем вызывать append()
? Вот что возможно сделает “рефакторинг” в нашем коде:
Прежде всего, мы возвращаем list
слишком рано, когда он еще не готов. Но кто-нибудь говорил мне, что эти два вызова append()
должны произойти перед return list
? Во-вторых, мы изменили порядок вызовов append()
. Опять же, кто-нибудь говорил мне, что важно вызывать их в этом конкретном порядке?
Никто. Нигде. Это называется временной связью.
Наши строки связаны вместе. Они должны оставаться в этом конкретном порядке, но знание об этом порядке скрыто. Легко нарушить порядок, и наш компилятор не сможет нас поймать.
Наоборот, в этом дизайне нет никакого “порядка”:
Он просто возвращает список, который формируется несколькими вызовами метода with()
. Это одна строка вместо четырех.
Как уже обсуждалось ранее, идеальный метод в ООП должен содержать только один оператор, и этим оператором является return
.
То же самое верно и для проверки. Например, этот код некорректен:
В то время как этот гораздо лучше:
See the difference?
И, конечно, идеальным подходом было бы использовать композицию декораторов вместо этих уродливых статических методов. Но если это по какой-то причине невозможно, просто не делайте эти статические методы похожими на процедуры. Убедитесь, что они всегда возвращают результаты, которые становятся аргументами для последующих вызовов.
Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-28 at 14:53