当公共代码具有多个不兼容的返回类型时,将公共代码分解出来

时间:2012-07-24 13:37:21

标签: java refactoring

我在重构时偶然发现了一段奇怪的代码。它看起来像是一个候选因素,用于分解两个readString() - 方法的共同部分,只是它似乎是不可能的(这对我来说是一个令人讨厌的脑筋急转弯):

private final StringBuilder readStringBuilder = new StringBuilder(128);

@Override
public String readString() throws IOException {
    final int l = readInt();
    if (l <= 0) {
        switch (l) {
            case -1: return null;
            case 0: return "";
            default: throw new IOException("invalid string length encoding: " + l);
        }
    }
    readStringBuilder.setLength(0);
    for (int i=0; i<l; ++i) {
        readStringBuilder.append(readChar());
    }
    return readStringBuilder.toString();
}

@Override
public String readString(final StringCache cache) throws IOException {
    final int l = readInt();
    if (l <= 0) {
        switch (l) {
            case -1: return null;
            case 0: return "";
            default: throw new IOException("invalid string length encoding: " + l);
        }
    }
    readStringBuilder.setLength(0);
    for (int i=0; i<l; ++i) {
        readStringBuilder.append(readChar());
    }
    return cache.get(readStringBuilder, readStringBuilder);
}

您看到两个方法几乎相同,方法体完全相同,但return语句除外。但是因为有早期终止退出,我找不到一个可以占用主体的方法签名 - natnatrally返回类型将是StringBuilder,只有在早期终止的情况下它才是String ...

如何将身体分解为单独的方法? (并注意空StringBuilder上的toString()会创建一个新的String而不是返回一个常量字符串文字)

编辑:StringCache的定义是:

public interface StringCache {
    public String get(final CharSequence charSeq, final CharSequence notFoundResult);
}

2 个答案:

答案 0 :(得分:6)

您是否只能创建一个适当填充readStringBuilder的私有方法?

然后两个readString()方法都使用它,并在缓存上执行get(),或在toString()上执行readStringBuilder

根据 Composed Method 重构,值得考虑这一点,其原则是:

  

组合方法说每个方法应该只做一件事

当你遵守这一点时,你的方法通常会变得可重用(可组合)。

  

通过这次重构练习我取得了什么成果? ....   既然我有小的构建块,方法重用就变成了   更容易,因为现在我可以混合和匹配它们

请参阅Neil Ford关于组合方法重构here的文章。另见Martin Fowler&#39; extractMethod&#39;重构。

答案 1 :(得分:3)

readStringBuilder作为实例字段看起来是某种形式的(过早?)优化。假设是这种情况,怎么样这样:

private StringBuilder readStringHelper() throws IOException {
  StringBuilder readStringBuilder = new StringBuilder(128);
    final int l = readInt();
    if (l <= 0) {
        switch (l) {
            case -1: return null;
            case 0: break;
            default: throw new IOException("invalid string length encoding: " + l);
        }
    }
    for (int i=0; i<l; ++i) {
        readStringBuilder.append(readChar());
    }
    return readStringBuilder;
}

@Override
public String readString() throws IOException {
    StringBuilder readStringBuilder = readStringHelper();
    return readStringBuilder==null ? null : readStringBuilder.toString();
}

@Override
public String readString(final StringCache cache) throws IOException {
    StringBuilder readStringBuilder = readStringHelper();
    return readStringBuilder== null ? null : cache.get(readStringBuilder, readStringBuilder);
}