Исходный код
public void updateTable() {
    /**
        * Удаляем лишние строки таблицы, оставшиейся от предыдущего списка
        */
      while (viewingData.getResult().getRowDataItems().size() + 1 < dataTable.getRowCount()) {
        dataTable.removeRow(dataTable.getRowCount()-1);
    }
    /**
        * Отображаем заголовки таблицы
        */
    int titleColumnIndex=0;
    String[] columnIds = newString[viewingData.getViewingColumns().size()];
    for (String viewingColumnId : viewingData.getViewingColumns().keySet()) {
        columnIds[titleColumnIndex] = viewingColumnId;
        ViewingColumnData viewingColumn= viewingData.getViewingColumns().get(viewingColumnId);
        HorizontalPanel titlePanel=new HorizontalPanel();
        titlePanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        Widget columnTitleButton;
        if (viewingColumn.isSortable()) {
            columnTitleButton = newButton(viewingColumn.getTitle());
            ((Button)columnTitleButton).addClickListener(newSortDataClickListener(viewingColumnId));
        } else {
            columnTitleButton = newLabel(viewingColumn.getTitle());
        }
        titlePanel.add(columnTitleButton);
        columnTitleButton.setStyleName(TABLE_STYLE);
        if (viewingData.getOrderColumnId() != null && viewingData.getOrderColumnId().equals( viewingColumnId) ) {
            Image orderDirectionImage;
            if (viewingData.getOrderDesc()) {
                orderDirectionImage = new Image(GWT.getModuleBaseURL() + UP_ARROW_IMG);
            } else {
                orderDirectionImage = new Image(GWT.getModuleBaseURL() + DOWN_ARROW_IMG);
            }
            titlePanel.add(orderDirectionImage);
        } else {
        }
        dataTable.setWidget(0, titleColumnIndex, titlePanel);
        FlexTable.FlexCellFormatter titlePanelFormatter = dataTable.getFlexCellFormatter();
        titlePanelFormatter.setStyleName(0, titleColumnIndex, "tableTitle");
        if (viewingColumn.getWidth() > 0) {
            titlePanelFormatter.setWidth(0, titleColumnIndex, viewingColumn.getWidth() + "%");
        }
        titlePanelFormatter.setHorizontalAlignment(0, titleColumnIndex, HasHorizontalAlignment.ALIGN_CENTER);
        titleColumnIndex++;
    }
    /**
        * Удаляем лишние столбцы в заголовке
        */
    intcolumnToRemove= dataTable.getCellCount(0) - viewingData.getViewingColumns().size();
    dataTable.removeCells(0, viewingData.getViewingColumns().size(), columnToRemove);
    /**
        * Добавляем чекбокс
        */
    addTitleCheckbox();
    /**
        * Отображаем значения раскрытых групп
        */
      if (viewingData.getGroupingFilterItems() != null) {
        for (intgroupingIndex=0; groupingIndex < viewingData.getGroupingFilterItems().size(); groupingIndex++ ) {
            String groupingFilterValue = viewingData.getGroupingFilterItems().get(groupingIndex);
            Label valueLabel = new Label(groupingFilterValue);
            Image img = new Image(LEFT_ARROW_IMG);
            HorizontalPanel valuePanel = new HorizontalPanel();
            valuePanel.add(img);
            valuePanel.add(valueLabel);
            valuePanel.setWidth("100%");
            valuePanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
            ClickListener hideGroupClickListener = new HideGroupClickListener(groupingIndex);
            valueLabel.addClickListener(hideGroupClickListener);
            img.addClickListener(hideGroupClickListener);
            String cellStyle;
            if (groupingIndex % 2 == 0) {
                cellStyle = "tableRow";
            } else {
                cellStyle = "tableRowOdd";
            }
            for (int column=0; column < viewingData.getViewingColumns().size(); column++) {
                String text=null;
                /**
                    *
                    */
                if (groupingIndex == viewingData.getGroupingFilterItems().size()-1 && viewingData.getFunctionData().containsKey(columnIds[column])) {
                    text = "(" + viewingData.getFunctionData().get(columnIds[column]) + ")";
                } else {Как делать рефакторинг «извлечение метода»
Ищем короткие фрагменты, которые некие маленькие, законченные и осмысленные действия, и переносим эти фрагменты в отдельные методы. Это могут быть методы в том же самом или в совсем других классах.
Обычно фрагмент определяется тем, какие переменные в нём задействованы.
Удаление лишних строк из таблицы
Вот такой фрагмент есть, выполняет осмысленное и обособленное действие:
    while (viewingData.getResult().getRowDataItems().size() + 1 < dataTable.getRowCount()) {
        dataTable.removeRow(dataTable.getRowCount()-1);
    }Это действие сильно завязано на экземпляр dataTable, поэтому логично перенести код в метод этого экземпляра.
public void shrinkRowsTo(maxRowsCount)
{
    while (dataTable.getRowCount() > maxRowsCount) {
        dataTable.removeRow(dataTable.getRowCount() - 1);
    }
}Код метода максимально обобщённый, не привязанный ни к каким другим объектам. Задача — удалить лишние строки, а откуда берётся количество, сколько строк оставить — методу не важно.
Исходный фрагмент будет выглядеть теперь так:
    dataTable.shrinkRowsTo(viewingData.getResult().getRowDataItems().size() + 1);Создание кнопки-заголовка
    Widget columnTitleButton;
    if (viewingColumn.isSortable()) {
        columnTitleButton = new Button(viewingColumn.getTitle());
        ((Button)columnTitleButton).addClickListener(newSortDataClickListener(viewingColumnId));
    } else {
        columnTitleButton = new Label(viewingColumn.getTitle());
    }
    titlePanel.add(columnTitleButton);
    columnTitleButton.setStyleName(TABLE_STYLE);
В этом коде заключено сразу два знания: как создать кнопку-заголовок, и куда потом её добавить.
Первое знание как раз следует извлечь в новый метод. Так как реализация крутится в основном вокруг экземпляра viewingColumn, то и метод должен стать его.
public Widget createColumnTitleButton()
{
    Widget columnTitleButton;
    if (isSortable()) {
        columnTitleButton = newButton(getTitle());
        ((Button)columnTitleButton).addClickListener(newSortDataClickListener(getId()));
    } else {
        columnTitleButton = newLabel(getTitle());
    }
    columnTitleButton.setStyleName(TABLE_STYLE);
    return columnTitleButton;
}    titlePanel.add(viewingColumn.createColumnTitleButton());Создание кнопки с иконкой направления сортировки
    if (viewingData.getOrderColumnId() != null && viewingData.getOrderColumnId().equals( viewingColumnId) ) {
        Image orderDirectionImage;
        if (viewingData.getOrderDesc()) {
            orderDirectionImage = new Image(GWT.getModuleBaseURL() + UP_ARROW_IMG);
        } else {
            orderDirectionImage = new Image(GWT.getModuleBaseURL() + DOWN_ARROW_IMG);
        }
        titlePanel.add(orderDirectionImage);
    }В этом фрагменте кода, опять же, заключены несколько знаний: надо ли добавлять иконку, как создать иконку, куда её добавить.
Первые два знания тесно связаны с экземпляром viewingData, поэтому перенесу их туда.
public boolean isSortedColumn(String columnId)
{
    return getOrderColumnId() != null && getOrderColumnId().equals(columnId);
}
public Image createDirectionImage()
{
    returnnewImage(GWT.getModuleBaseURL() + (getOrderDesc() ? UP_ARROW_IMG : DOWN_ARROW_IMG));
}Заодно избавился от небольшого дублирования реализации при создании экземпляра иконки.
В результате исходный код рефакторится следующим образом:
    if (viewingData.isSortedColumn(viewingColumnId)) {
        titlePanel.add(viewingData.createDirectionImage());
    }Создание форматтера
Следующий автономный фрагмент посвящён созданию некоего форматтера:
    FlexTable.FlexCellFormattertitlePanelFormatter= dataTable.getFlexCellFormatter();
    titlePanelFormatter.setStyleName(0, titleColumnIndex, "tableTitle");
    if (viewingColumn.getWidth() > 0) {
        titlePanelFormatter.setWidth(0, titleColumnIndex, viewingColumn.getWidth() + "%");
    }
    titlePanelFormatter.setHorizontalAlignment(0, titleColumnIndex, HasHorizontalAlignment.ALIGN_CENTER);Хотя совершенно непонятно, как он цепляется к таблице. Предположу, что когда-то эта функциональность была нужна, а потом её частично выпилили и забыли.
При любом раскладе этот код надо извлечь в отдельный метод. Я бы отнёс этот код к экземпляру dataTable:
public FlexTable.FlexCellFormatter createFlexColumnFormatter(int titleColumnIndex, ViewingColumnData viewingColumn)
{
    FlexTable.FlexCellFormattertitlePanelFormatter= dataTable.getFlexCellFormatter();
    titlePanelFormatter.setStyleName(0, titleColumnIndex, "tableTitle");
    if (viewingColumn.getWidth() > 0) {
        titlePanelFormatter.setWidth(0, titleColumnIndex, viewingColumn.getWidth() + "%");
    }
    titlePanelFormatter.setHorizontalAlignment(0, titleColumnIndex, HasHorizontalAlignment.ALIGN_CENTER);
    return titlePanelFormatter;
}Удаление лишних колонок из таблицы
int columnToRemove = dataTable.getCellCount(0) - viewingData.getViewingColumns().size();
    dataTable.removeCells(0, viewingData.getViewingColumns().size(), columnToRemove);Смысл этого кода в том, чтобы оставить в заголовке dataTable столько колонок, сколько есть в viewingData.
Здесь тоже два знания: как удалять колонки и где взять количество, сколько штук оставить.
Так как действие касается экземпляра dataTable, есть резон создать в нём отдельный метод для укорачивания колонок:
public void shrinkTitleColumns(int shrinkTo)
{
    removeCells(0, shrinkTo, getCellCount(0) - shrinkTo);
}Как и в прошлый раз со строками, метод максимально обобщённый, работает просто с количеством колонок, независимо от того, откуда оно взялось.
Исходный примет следующий вид:
    dataTable.shrinkTitleColumns(viewingData.getViewingColumns().size());Теперь здесь осталось только одно знание: где взять нужное количество колонок; о подробностях собственно удаления знает только метод shrinkTitleColumns.
Создание полей значений
Дальше идёт довольно переплетённый фрагмент кода:
    String groupingFilterValue= viewingData.getGroupingFilterItems().get(groupingIndex);
    LabelvalueLabel=newLabel(groupingFilterValue);
    Imageimg=newImage(LEFT_ARROW_IMG);
    HorizontalPanelvaluePanel=newHorizontalPanel();
    valuePanel.add(img);
    valuePanel.add(valueLabel);
    valuePanel.setWidth("100%");
    valuePanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
    ClickListenerhideGroupClickListener=newHideGroupClickListener(groupingIndex);
    valueLabel.addClickListener(hideGroupClickListener);
    img.addClickListener(hideGroupClickListener);Его апофеозом является создание экземпляра valuePanel, хотя последовательность действий неочевидна. Поскольку всё начинается с viewingData, пусть извлечённый метод относится к нему. Заодно попробую немного переупорядочить строки так, чтобы стали лучше видны взаимозависимости между объектами.
public HorizontalPanel createValuePanel(int groupingIndex)
{
    HorizontalPanel valuePanel = new HorizontalPanel();
    ClickListener hideGroupClickListener = new HideGroupClickListener(groupingIndex);
    String groupingFilterValue = getGroupingFilterItems().get(groupingIndex);
    Label valueLabel = newLabel(groupingFilterValue);
    valueLabel.addClickListener(hideGroupClickListener);
    valuePanel.add(valueLabel);
    Image img=newImage(LEFT_ARROW_IMG);
    img.addClickListener(hideGroupClickListener);
    valuePanel.add(img);
    valuePanel.setWidth("100%");
    valuePanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
    return valuePanel;
}Теперь фрагменты реализаций, нацеленные на формирование и добавление метки и иконки, максимально сгруппированы.
В этом фрагменте по-прежнему содержатся много знаний: как формировать метку, как добавлять метку, как формировать иконку, как добавлять иконку, как форматировать виджет — но критической необходимости разделять эти знания пока нет.
Как будет выглядеть отрефакторенный код
public void updateTable() {
    dataTable.shrinkRowsTo(viewingData.getResult().getRowDataItems().size() + 1);
    int titleColumnIndex=0;
    String[] columnIds = newString[viewingData.getViewingColumns().size()];
    for (String viewingColumnId : viewingData.getViewingColumns().keySet()) {
        columnIds[titleColumnIndex] = viewingColumnId;
        ViewingColumnData viewingColumn= viewingData.getViewingColumns().get(viewingColumnId);
        HorizontalPanel titlePanel = new HorizontalPanel();
        titlePanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        titlePanel.add(viewingColumn.createColumnTitleButton());
        if (viewingData.isSortedColumn(viewingColumnId)) {
            titlePanel.add(viewingData.createDirectionImage());
        }
        dataTable.setWidget(0, titleColumnIndex, titlePanel);
        dataTable.createFlexColumnFormatter();
        titleColumnIndex++;
    }
    dataTable.shrinkTitleColumns(viewingData.getViewingColumns().size());
    addTitleCheckbox();
    if (viewingData.getGroupingFilterItems() != null) {
        for (intgroupingIndex=0; groupingIndex < viewingData.getGroupingFilterItems().size(); groupingIndex++ ) {
            HorizontalPanelvaluePanel= viewingData.createValuePanel(groupingIndex);
            // ...Теперь можно сделать ещё несколько итераций рефакторинга, извлекая в новые методы код для формирования titlePanel, всего набора колонок, фильтров и т. п.
Теория
- Принцип единственного знания
- Рефакторинг «извлечение метода»
- Завистливые методы
- GRASP
- Паттерн «Информационный эксперт»