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() は、定数文字列リテラルを返す代わりに、新しい String を作成することに注意してください)

編集: StringCache の定義は次のとおりです。

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

2 に答える 2

6

readStringBuilderを適切に設定するプライベート メソッドを 1 つだけ作成することはできませんか?

次に、両方のreadString()メソッドがそれを使用しget()、キャッシュに対して実行するかtoString()readStringBuilder?

Composed Methodリファクタリングに照らして、これを検討する価値があります。これは、次の原則を採用しています。

構成されたメソッドは、各メソッドが 1 つだけのことを行う必要があることを示しています

これに従うと、多くの場合、メソッドは再利用可能 (構成可能) になります。

このリファクタリングの演習を通じて、私は何を達成しましたか? ....小さな構成要素ができたので、それらを組み合わせて一致させることができるようになったため、メソッドの再利用が容易になりました

Composed Methodのリファクタリングに関する 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 に答える