Повторение кода против многоответственного метода

11

Я стараюсь следовать принципу единой ответственности (SRP), а также опускать повторения кода. Однако часто есть места, где есть повторения кода, которые являются не чем иным, как кодовыми блоками вызовов, которые устойчивы к извлечению их в по крайней мере значащий именованный метод:

DoAction1();
DoAction2();

if (value)
    DoAction3();

DoAction4();

Каков наилучший способ извлечь такой код в метод и как его назвать?

yBee
источник
1
Почему они устойчивы к тому, чтобы быть извлеченными в другой значимый метод?
Чандраншу
Все действия делают что-то не связанное. Я бы написать: void MethodThatDoAction1ThenAction2AndAction3IfValueAndThenAction4(). Я предпочел бы видеть больше смысла в: CodeBlock1().
yBee
4
Тогда это просто вопрос правильного присвоения имени извлеченному методу, верно? Боюсь, что нет универсального решения, и вам придется делать это на индивидуальной основе. Если вы повторяете один и тот же кусок кода более чем в одном месте, ваши действия обязательно будут иметь смысл, и вам нужно внимательно посмотреть (возможно, обсудить), чтобы найти это значение и дать ему имя.
Chandranshu
1
Если это утешит, победитель Spring для длинных имен классов будет AbstractInterruptibleBatchPreparedStatementSetterчуть меньше вашего метода.
Чандраншу
1
@Chandranshu Я думаю, что ваш комментарий (ы) будет работать как ответ на этот вопрос.
Саймон Форсберг,

Ответы:

13

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

Если это утешит, победитель Spring для длинных имен классов - AbstractInterruptibleBatchPreparedStatementSetterэто 49 символов.

Chandranshu
источник
11

На самом деле вы страдаете от самой сложной задачи программиста - Naming Things . Извините за такой удивительный ответ, но я не удержался. Вы можете обнаружить, что многие люди страдают от этого , даже в Интернете вы можете найти этот тип эссе .

Теперь, если ваш повторяющийся код все вместе приводит к одной работе, и эти методы не используются другими методами, тогда они являются просто методом Helpers, и тогда полученный метод может быть назван как doXXXили makeXXX... Я думаю, вы поняли смысл.

Как сказал Чандраншу : «Если вы повторяете это значение и даете ему имя». это точно и уместно.

введите описание изображения здесь

Фото любезно предоставлено: CodeChef Facebook Page Photo

Анирбан Наг 'tintinmj'
источник
2

Я думаю, что вы слишком далеко зашли с принципом повторения кода. Подумайте о том, как избежать повторения кода. Задача состоит в том, чтобы уменьшить объем кода, который должен быть проверен при изменении логики, и улучшить понимание, выделив блоки с явно подобным предназначением.

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

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

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

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

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

Мне кажется, что если бы люди пытались выделить то, что вы пытаетесь, у нас была бы целая библиотека бесполезных конструкций, таких как Do1Then2If2False Do1IfTrueDo2.

Это должно быть более сложным и более ясным, что блок не собирается меняться, чтобы оправдать его факторизацию.

Это программное обеспечение . Вы можете вернуться и отредактировать пару одинаковых блоков прямо сейчас. Это займет 5 минут. И вы можете сэкономить часы потраченного впустую факторинга, а затем часы потраченного впустую наследования и разработки коммутации, просто оставив его и убедившись, что у вас есть хорошая клавиатура против RSI.

Энди Смит
источник
Мне нравится часть, которая извлекает суть повторения кода: чтобы уменьшить количество кода, который должен быть проверен, когда есть изменения в логике
yBee
1

Если вы действительно следуете принципу единой ответственности, то этот блок кода должен иметь какую-то конкретную цель, верно? В противном случае эти методы будут в отдельных классах.

Итак, какова цель этого блока кода? Определите это, и вы должны быть в состоянии придумать имя.

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

Аллан
источник
1

У меня была ситуация, которая может быть похожа на вашу:

Есть класс, который определяет функциональность объекта, который он представляет:

class Functionality
{
protected:
void functionA();
void functionB();
...
void functionZ();
}

Тогда есть класс, который определяет рабочие процессы для высокоуровневых операций, которые выполняет объект:

class Workflows: private Functionality
{
    void WorkflowA()
    {
        functionA();

        if (m_bValue) {
            functionB();
        }

        functionC();
    }
    ...
    void WorkflowB();
}

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

Отказ от ответственности: Имена классов, используемые в этом примере, очень неточны, но имена методов дают подсказку. На усмотрение рекомендуется.

dotbugfix
источник