2

我在重构时偶然发现了一段奇怪的代码。它看起来像是分解两个 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 语句。但是由于有提前终止退出,我找不到可以采用主体的方法签名 - 自然地,返回类型将是 StringBuilder,只有在提前终止的情况下才会是 String ...

任何想法如何将身体分解成一个单独的方法?(请注意,空 StringBuilder 上的 toString() 确实会创建一个新字符串,而不是返回一个常量字符串文字)

编辑: StringCache 的定义是:

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

2 回答 2

6

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

然后这两种readString()方法都使用它,或者get()在缓存上执行 a ,或者toString()readStringBuilder?

鉴于组合方法重构,这是值得考虑的,它以以下原则为原则:

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

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

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

请在此处查看 Neil Ford 关于组合方法重构的文章。另请参见 Martin Fowler 的“ extractMethod ”重构。

于 2012-07-24T13:41:52.457 回答
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);
}
于 2012-07-24T14:18:32.440 回答