有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何通过重构代码来降低圈复杂度?

这个问题重复了一遍,但我仍然在问,因为通过使用解决方案中建议的方法,我无法显著降低复杂性。 函数的复杂度是28,我必须将其降低到10以下

private void adjustViewport(IEditorPart editorPart, LineRange range,
    TextSelection selection) {
    ITextViewer viewer = EditorAPI.getViewer(editorPart);
    if (viewer == null) +1
        return; +1

    IDocument document = viewer.getDocument();
    LineRange viewportOfViewer = EditorAPI.getViewport(viewer);

    if (viewportOfViewer == null || document == null) +1 +1
        return; +1

    int lines = document.getNumberOfLines();
    int rangeTop = 0;
    int rangeBottom = 0;
    int selectionTop = 0;
    int selectionBottom = 0;

    if (selection != null) { +1
        try {
            selectionTop = document.getLineOfOffset(selection.getOffset());
            selectionBottom = document.getLineOfOffset(selection
                .getOffset() + selection.getLength());
        } catch (BadLocationException e) { +1
            // should never be reached
            LOG.error("Invalid line selection: offset: "
                + selection.getOffset() + ", length: "
                + selection.getLength());

            selection = null;
        }
    }

    if (range != null) { +1
        if (range.getStartLine() == -1) { +1
            range = null;
        } else {
            rangeTop = Math.min(lines - 1, range.getStartLine());
            rangeBottom = Math.min(lines - 1,
                rangeTop + range.getNumberOfLines());
        }
    }

    if (range == null && selection == null) +1 +1
        return; +1

    // top line of the new viewport
    int topPosition;
    int localLines = viewportOfViewer.getNumberOfLines();
    int remoteLines = rangeBottom - rangeTop;
    int sizeDiff = remoteLines - localLines;

    // initializations finished

    if (range == null || selection == null) { +1 +1
        topPosition = (rangeTop + rangeBottom + selectionTop + selectionBottom) / 2;
        viewer.setTopIndex(topPosition);
        return; +1
    }

    /*
     * usually the viewport of the follower and the viewport of the followed
     * user will have the same center (this calculation). Exceptions may be
     * made below.
     */
    int center = (rangeTop + rangeBottom) / 2;
    topPosition = center - localLines / 2;

    if (sizeDiff <= 0) { +1
        // no further examination necessary when the local viewport is the
        // larger one
        viewer.setTopIndex(Math.max(0, Math.min(topPosition, lines)));
        return; +1
    }

    boolean selectionTopInvisible = (selectionTop < rangeTop + sizeDiff / 2);
    boolean selectionBottomInvisible = (selectionBottom > rangeBottom
        - sizeDiff / 2 - 1);

    if (rangeTop == 0 +1
        && !(selectionTop <= rangeBottom && selectionTop > rangeBottom +1 +1
            - sizeDiff)) {
        // scrolled to the top and no selection at the bottom of range
        topPosition = 0;

    } else if (rangeBottom == lines - 1 +1
        && !(selectionBottom >= rangeTop && selectionBottom < rangeTop +1 +1
            + sizeDiff)) {
        // scrolled to the bottom and no selection at the top of range
        topPosition = lines - localLines;

    } else if (selectionTopInvisible && selectionBottom >= rangeTop) { +1 +1
        // making selection at top of range visible
        topPosition = Math.max(rangeTop, selectionTop);

    } else if (selectionBottomInvisible && selectionTop <= rangeBottom) { +1 +1
        // making selection at bottom of range visible
        topPosition = Math.min(rangeBottom, selectionBottom) - localLines
            + 1;
    }

    viewer.setTopIndex(Math.max(0, Math.min(topPosition, lines)));
}

编辑:我已经将复杂性降低到11。我应该怎样进一步减少它

private int setTopPositionUtil(int sizeDiff, int rangeTop, int rangeBottom, int selectionTop, int selectionBottom) {
boolean selectionTopInvisible = (selectionTop < rangeTop + sizeDiff / 2);
boolean selectionBottomInvisible = (selectionBottom > rangeBottom - sizeDiff / 2 - 1);
if (rangeTop == 0 && !(selectionTop <= rangeBottom && selectionTop > rangeBottom - sizeDiff)) { // +1 +1 +1
    // scrolled to the top and no selection at the bottom of range
    topPosition = 0;
} else if (rangeBottom == lines - 1 && !(selectionBottom >= rangeTop && selectionBottom < rangeTop + sizeDiff)) { // +1 +1 +1
    // scrolled to the bottom and no selection at the top of range
    topPosition = lines - localLines;
} else if (selectionTopInvisible && selectionBottom >= rangeTop) { // +1 +1
    // making selection at top of range visible
    topPosition = Math.max(rangeTop, selectionTop);
} else if (selectionBottomInvisible && selectionTop <= rangeBottom) { // +1 +1
    // making selection at bottom of range visible
    topPosition = Math.min(rangeBottom, selectionBottom) - localLines + 1;
}
return topPosition;
}

private int setTopPosition(int localLines, int rangeTop, int rangeBottom,int selectionTop, int selectionBottom) {

// top line of the new viewport
int topPosition;
int remoteLines = rangeBottom - rangeTop;
int sizeDiff = remoteLines - localLines;

// initializations finished

/*
 * usually the viewport of the follower and the viewport of the followed
 * user will have the same center (this calculation). Exceptions may be
 * made below.
 */
int center = (rangeTop + rangeBottom) / 2;
topPosition = center - localLines / 2;

if (sizeDiff > 0) { // +1
    setTopPositionUtil(sizeDiff, rangeTop, rangeBottom, selectionTop, selec);
}

return Math.max(0, Math.min(topPosition, lines)); // +1
}

private void adjustViewport(IEditorPart editorPart, LineRange range,TextSelection selection) {
ITextViewer viewer = EditorAPI.getViewer(editorPart);
if (viewer != null) { // +1

    IDocument document = viewer.getDocument();
    LineRange viewportOfViewer = EditorAPI.getViewport(viewer);

    if (viewportOfViewer != null && document != null) { // +1 +1

        int lines = document.getNumberOfLines();
        int rangeTop = 0;
        int rangeBottom = 0;
        int selectionTop = 0;
        int selectionBottom = 0;

        if (selection != null) { // +1
            try {
                selectionTop = document.getLineOfOffset(selection.getOffset());
                selectionBottom = document.getLineOfOffset(selection
                    .getOffset() + selection.getLength());
            } catch (BadLocationException e) { // +1
                // should never be reached
                LOG.error("Invalid line selection: offset: " +
                    selection.getOffset() + ", length: " +
                    selection.getLength());

                selection = null;
            }
        }

        if (range != null) { // +1
            if (range.getStartLine() == -1) { // +1
                range = null;
            } else {
                rangeTop = Math.min(lines - 1, range.getStartLine());
                rangeBottom = Math.min(lines - 1,
                    rangeTop + range.getNumberOfLines());
            }
        }

        if (range != null && selection != null) { // +1 +1
            viewer.setTopIndex(setTopPosition(viewportOfViewer.getNumberOfLines(),
                rangeTop, rangeBottom, selectionTop, selectionBottom));
        } else {
            viewer.setTopIndex((rangeTop + rangeBottom + selectionTop + selectionBottom) / 2);
        }
    }
}
}

注意:代码现在由3个方法组成。第二个和第三个的复杂度低于10,但是setTopPositionUtil的复杂度仍然是11。有什么帮助吗
对不起,缩进了


共 (2) 个答案

  1. # 1 楼答案

    正如GhostCat已经提到的,您需要创建一系列单元测试来测试重构

    关于我所做的重构的一些注释:

    • 尽可能避免使用超过20-30行代码的方法
    • 为方法使用有意义的名称(我假设方法setTopPosition最好命名为calculateTopPosition
    • 除非绝对必要,否则不要将参数传递给方法(注意下面的viewer不再传递给方法calculateTopIndex,因为它只需要它的结果
    • 更小的方法意味着更简单的测试

    下面你可以看到解决问题的一种方法:

    private void adjustViewport(IEditorPart editorPart, LineRange range, TextSelection selection) {
        ITextViewer viewer = EditorAPI.getViewer(editorPart);
    
        if (viewer == null) return; // +1
    
        IDocument document = viewer.getDocument();
        LineRange viewportOfViewer = EditorAPI.getViewport(viewer);
    
        if (viewportOfViewer == null || document == null) return; // +1
    
        viewer.setTopIndex(calculateTopIndex(document, viewportOfViewer, range, selection);
    
    }
    
    private int calculateTopIndex(IDocument document, LineRange viewportOfViewer, LineRange range, TextSelection 
            selection) {
        int selectionTop = 0;
        int selectionBottom = 0;
        if (selection != null) { // +1
            try {
                selectionTop = document.getLineOfOffset(selection.getOffset());
                selectionBottom = document.getLineOfOffset(selection
                        .getOffset() + selection.getLength());
            } catch (BadLocationException e) { // +1
                // should never be reached
                LOG.error("Invalid line selection: offset: " +
                        selection.getOffset() + ", length: " +
                        selection.getLength());
    
                selection = null;
            }
        }
    
        if (!isRangeValid(range)) { // +1
            return (selectionTop + selectionBottom) / 2;
        }
    
        int lines = document.getNumberOfLines();
    
        int rangeTop = Math.min(lines - 1, range.getStartLine());
        int rangeBottom = Math.min(lines - 1,
                rangeTop + range.getNumberOfLines());
    
        boolean isSelectionPresent = selection != null;
        if (isSelectionPresent) { // +1
            return setTopPosition(viewportOfViewer.getNumberOfLines(), rangeTop, rangeBottom, selectionTop,
                    selectionBottom);
        } else {
            return (rangeTop + rangeBottom) / 2;
        }
    }
    
    private boolean isRangeValid(LineRange range) {
        return (range != null && range.getStartLine() != -1);
    }
    
  2. # 2 楼答案

    你的问题非常广泛,但为了让你继续,你应该做以下几点:

    1. 为测试中的代码创建单元测试
    2. 你使用一些覆盖率工具,以便通过测试获得100%的覆盖率

    换句话说:您编写了如此多的测试用例,以至于您完全确信生产代码中的每个方面都有一个测试

    然后开始重构。你一直在运行你的测试套件;确保你不会弄坏任何东西。你一直在运行你的复杂性度量工具;确保你的方向正确

    当问题是:我如何重构,然后转向经典,比如福勒的Refactoring或马丁的Clean Code

    总的来说,我认为你也有点把重点放在了错误的主题上:你的主要目标应该是创建易于理解的可读代码。我的建议是将这个巨大的方法进一步分割成一些较小的方法