Пример рефакторинга «извлечение метода» в алгоритме установки кода проекта


Исходный код

private void setTims( String project )
{
    int endIndex= project.indexOf( "-" );
    boolean isNumber=false;
    if ( endIndex != -1 )
    {
        try
        {
            Integer.parseInt( project.substring( 0, endIndex ) );
            isNumber = true;
        }
        catch ( NumberFormatException e )
        {
            //ignore
        }
    }
    if ( isNumber )
    {
        runtimeContext.put( RuntimeContext.TIMS_NUMBER, project.substring( 0, endIndex ) );
    }
    else
    {
        runtimeContext.put( RuntimeContext.TIMS_NUMBER, project );
    }
}

Что не так в исходном коде

Тут сразу два недочёта, которые непросто разглядеть. Во-первых, метод setTims выполняет две независмых вещи:

  • получает номер TIMS;
  • запоминает номер в некоем глобальном хранилище.

Во вторых, реализация запоминания номера дублируется дважды.

Как отрефакторить исходный код

Для успешного рефакторинга необходимо разобраться в предметной области. После краткого анализа кода метода становится понятно, что его цель — установить в глобальном контексте некий номер, формируемый из некоего дескриптора проекта. Поэтому первым делом отделяю получение от установки:

runtimeContext.put( RuntimeContext.TIMS_NUMBER, getTims( project ) );

Одновременно устраняю недочёт с дублированием реализации запоминания номера.

Метод getTims должен быть помещён в класс проекта, так как по сути имеет отношение только к проекту.

public String getTims()
{
    int endIndex = project.indexOf( "-" );
    boolean isNumber = false;
    if ( endIndex != -1 )
    {
        try
        {
            Integer.parseInt( project.substring( 0, endIndex ) );
            isNumber = true;
        }
        catch ( NumberFormatException e )
        {
            //ignore
        }
    }
    return isNumber ? project.substring( 0, endIndex ) : project;
}

Теперь можно на скорую руку немного оптимизировать алгоритм вычисления номера:

public String getTims()
{
    int endIndex = project.indexOf( "-" );
    if ( endIndex != -1 )
    {
        try
        {
            String number= project.substring( 0, endIndex );
            Integer.parseInt( number );
            return number;
        }
        catch ( NumberFormatException e ) {} 
    }
    return project;
}

Реузльтат можно получить более понятным путём, применив регулярные выражения:

private static final Pattern TIMS_PATTERN = Pattern.compile("^(\\d+)-");
public String getTims()
{
    Matcher tims= TIMS_PATTERN.matcher(project);
    if (tims.matches()) {
        return tims.group(1);
    }
    return project;
}

Теория