2016-08-31 2 views
0

私はページからテロップデータの束を処理するアプリケーションを書いています。私が扱っている主なクラスは、Instrumentと呼ばれ、どの楽器にも関連するすべてのデータを格納するために使用されます。データはウェブサイトからダウンロードされ、解析されます。インターフェイス分離フレームワークとパターン

class Instrument 
{ 
    string Ticker {get; set;} 
    InstrumentType Type {get; set;} 
    DateTime LastUpdate {get; set;} 
} 

私の問題は、データの解析を扱うクラスを正しく構造化する方法がわかりません。私は多くの異なるフィールド(Tickers、InstrumentType、Timestampsなど)を埋め込むためにデータを解析する必要があるだけでなく、データがさまざまなソースから取得されるため、解析のすべてを処理する標準パターンはありません。低レベルの解析メソッド(文字列から型/型/タイムスタンプを正規表現し、グループマッチを個別に解析する必要がある場合)を使用する必要がある解析メソッドもあります。

私の最初の試みは、一つの大きなクラスを作成することでしたParsingHandler方法の束は、すべての特定の構文解析ニュアンスに対処し、インストゥルメントクラスにフィールドとしてそれを追加するために含まれているが、私は何回もことがわかった、プロジェクトが進化するにつれて、私はメソッドを追加するか、新しい予期しない状況にクラスを適合させるためのパラメータを追加することを余儀なくされました。

class ParsingHandler 
{ 
     string GetTicker(string haystack); 
     InstrumentType GetType(string haystack); 
     DateTime GetTimestamp(string haystack); 
} 

は、より多くのインターフェイス中心の設計手法を適応しようとした後、私は別のルートを試してみましたが、このインタフェースを定義した:

interface IParser<outParam, inParam> 
{ 
     outParam Parse(inParam data); 
} 

そして、私が対処構文解析クラスの束を定義したインターフェースを使用して、あらゆる特定の構文解析の状況で。たとえば:

class InstrumentTypeParser : IParser<InstrumentType, string> 
{ 
     InstrumentType Parse(string data); 
} 

class RegexMatchParser : IParser<Instrument, Match> where Instrument : class, new() 
{ 
    public RegexMatchParser(
      IParser<string, string> tickerParser, 
      IParser<InstrumentType, string> instrumentParser, 
      IParser<DateTime, string> timestampParser) 
    { 
     // store into private fields 
    } 

    Instrument Parser(Match haystack) 
    { 
      var instrument = new Instrument(); 
      //parse everything 
      return instrument; 
    } 
} 

これは正常に動作するようですが、私は状況に今の私は、私はクラスのコンストラクタに渡す必要があります実装のトンを持っているようにそれはそうでした。それは危険なほど理解できないほどに近いようです。それに対処する私の考えは、特定の解析実装をすべて格納するenumと辞書を定義することですが、私はそれが間違っているか、またはこの細かいアプローチで一般的に間違った方向に向かうことを心配しています。私の方法論は分断されていますか?私が元々持っていたような大量のメソッドを持つ1つの主要な解析クラスを持つ方が良いでしょうか?この特定のタイプの状況のた​​めの代替アプローチがありますか?

答えて

1

私はパーサを一般的なものにしようとすると、IParser<TOut, TIn>とは同意しません。私は、InstrumentParserのようなものは、楽器を扱うのにかなり十分であるように見えます。

とにかく、Matchオブジェクトやそれに類するもののような別のものを解析するときは、一般的な引数を扱う興味深いテクニックを1つ適用することができます。つまり、あなたが解析しているものが分かっている場合(stringInstrumentのような理由でジェネリックスが存在するのであれば)、にはという一般的な引数はないでしょう。その場合、あなたは特別なインタフェースおよび/または減少した汎用的な引数リストを持つクラスを定義することができます。

interface IStringParser<T>: IParser<T, string> { } 

あなたはおそらく、とにかく文字列からのデータを解析します。その場合、あなたはマッチオブジェクトから解析する汎用クラスを提供することができます繰り返し、この技術を適用することにより

class RegexParser: IStringParser<T> 
{ 
    Regex regex; 
    IParser<T, Match> parser; 

    public RegexParser(Regex regex, IParser<T, Match> containedParser) 
    { 
     this.regex = regex; 
     this.parser = containedParser; 
    } 
    ... 
    T Parse(string data) 
    { 
     return parser.Parse(regex.Match(data)); 
    } 
} 

を、あなたは最上位の消費クラスは唯一の非ジェネリックインターフェイスまたはインターフェイスを持つに依存することができます1人の一般会員。中級クラスは、より複雑な(そしてより具体的な)実装を包み込み、すべてが構成の問題になります。

目標は、常に可能な限り単純な消費クラスに向かうことです。したがって、詳細をラップし、消費者から隠すようにしてください。

+0

ご質問ありがとうございました。ありがとうございました。時間を割いてアドバイスやご提案をさせていただきました。私の理解から、あなたが私のインタフェース駆動方法論に大部分は同意したようです。つまり、さまざまなパーサーのインスタンス化を処理する方法と、パーサの実装にそれらを渡す方法について考えていますか?たとえば、リストしたRegexParserには、3つの異なるベースパーサーが必要な場合があります。これは、コードを調べる際に混乱する可能性があります。これは "コーディングのベストプラクティス"の観点から受け入れられますか?もしそうでなければ、何があろうか? – user3745593

+0

コンストラクタを介して依存関係が注入されている限り、DIフレームワークを使用して依存関係を注入して設定問題にすることを心配する必要はありません。消費コードがこれをすべて知っているわけではなく、非汎用の 'InstrumentParser'のようなすべてのインターフェースの中で最も単純なものだけを参照することが重要です。 –

関連する問題