1

特定のファイルからテキストを解析するクラスを作成しています。テキストにはいくつかの異なる「タイプ」があり、解析ルールはそれぞれ異なります。

たとえば、テキストのタイプの 1 つ (単に「プレーン テキスト」と呼びます) は、パーサーが余分な空白を取り除く単純な文字列です。たとえば、私が持っていた "The quick brown fox\r\njumped over the lazy brown dogs\r\n"場合、パーサーは単純に戻り"The quick brown fox jumped over the lazy brown dogs"ます (改行は単一のスペースに変換されます)。

他のテキストは、指定された区切り文字を持つテーブルを表すため、 のように見える場合があります"First Name,Last Name,DOB"。パーサーの仕事は、コンマで区切られた各値を含む配列を返すことです。

(実際の実装はこれよりも複雑ですが、これは適切な単純化です)。

もともと私はTextType、値PlainTextTableText. 次に、次のようなメソッドを作成できます

public string ParseText(string textToParse, TextType textType)

stringtextType が PlainText の場合、戻り値は a である必要がありますが、textType が TableText の場合、戻り値はa である必要があるため、これが機能しないことにすぐに気付きましたstring[]

1 つのオプションは、常に string[] を返すことであり、PlainText が常にサイズ 1 の配列を返すことを前提としています。ただし、意味的に正しくないように見えるだけでなく、紛らわしい。

もう 1 つのオプションは、TextType ごとにメソッドを記述することです。

public string ParsePlainText(string textToParse)

public string[] ParseTableText(string textToParse)

このアプローチが気に入らない理由は、列挙型を使用した元のアプローチによって提供された柔軟性の一部が失われるためです。たとえば、後でテキスト タイプを追加する予定です。将来的には、クライアントが HeadingText などと識別したいテキストのタイプがあるかもしれませんが、プレーン テキストと同じように解析されます。元のアプローチでは、解析メソッドを含むクラスのパブリック インターフェイスを変更する必要はありません。TextTypeParseText メソッドの内部を列挙して変更します。さらに、呼び出すメソッドが 1 つしかなく、クライアントが (彼が知っている) TextType を渡すだけでよく、他のすべてが彼のために処理される (似たような名前の新しいテキスト タイプが追加されるたびに成長するメソッド)。

string最後に、 と の両方を継承するオブジェクトを返すだけstring[]で (これは C# であるため、単に を返すことができますobject)、クライアントを適切な型にキャストすることができます。これは、クライアントが「実際に」何を返す必要があるかを知る必要があり、Parse クラスから返される型を変更し、実行時までエラーが発生しないようにすることで、すべての依存関係を壊す可能性が非常に高いため、これは最悪のアプローチだと思います。 (基本的に型チェックがないため)。

この状況に対する「正しい」または最適なアプローチはありますか?

4

3 に答える 3

2

いくつかの方法があります..しかし、最初に頭に浮かぶのは、以下を使用することですinterfaces

interface ITextParser {
    string Parse(string text);
}

public class TableTextParser : ITextParser {
    public string Parse(string text) {
        // specific table parsing stuff here
    }
}

public class PlainTextParser : ITextParser {
    public string Parse(string text) {
        // specific plain text parsing stuff here
    }
}

その場合、メイン関数は次のような種類のファクトリになる可能性があります。

public ITextParser CreateParserFor(string textToParse) {
    // logic here to determine the sort of parser you require:
    if (typeOfTextIsTable)
        return new TableTextParser();

    if (typeOfTextIsPlain)
        return new PlainTextParser();
}

次に、おそらくそのように呼び出すことができます:

var parser = CreateParserFor(string_here);
var result = parser.Parse(string_here);
于 2013-01-29T01:10:00.257 に答える
1

Let's try to clarify the problem a bit. You have two types of texts (at least for now, that will likely grow to more types), that:

  1. Have the same input type, String.
  2. Have different output types, String and an Array.
  3. Have different implementation.

The future added types may require a different types of output/return. Now the question is, is it really logical to try to combine these functionality into one method? I see that your goal is to provide a uniform/generic interface to the clients, but, if the the return types are different, I am not sure if you can provide such an interface.

I don't think having many similar methods in an interface is a bad thing. There are many well-known libraries that are this way.

In my opinion, your second approach, having something like

public string ParsePlainText(string textToParse)
public string[] ParseTableText(string textToParse)

despite your suspicion, is a much cleaner way, than the other suggested ways. Especially, if you look at it from the clients view (compared to case where an array of size 1 is return, or casting used, etc).

于 2013-01-29T03:03:11.420 に答える
0

提案されたアプローチのいずれについても、結果のコレクションを表すメソッドParseResultsからオブジェクトを返すことができます。Parseこれにより、 を公開してiteratorを反復処理できParseResultsます。

これにより、署名が統一され、IMO が混乱することはありません。

お役に立てれば。

于 2013-01-30T00:38:21.080 に答える