0

さまざまなタイプのデータを解析するためのライブラリを作成しました。これが図書館の使い方です。

$parser = DataParser::factory($text);
$data = $parser->parse();
foreach($data as $name=>$datum)
    echo "name: $name\nData: ".$datum."\n";

$dataのインスタンスを次に示しますNamedDataCollection。そして、ここにクラス定義があります

interface Parsable{
    // @returns NamedDataCollection
    function parse();
    // @returns bool. True if it can parse the data.
    function can_parse();
}

class AParser implements Parsable{
    public function parse(){
       $this->check_header();
       $this->check_content();
       $this->parse_content();
       ...
    }
    public function can_parse(){
       $this->check_header();
       $this->check_content();
       ...
    }
}

class BParser implements Parsable{
    public function parse(){
       ...
    }
    public function can_parse(){
       ...
    }
}

class ParserRegistry{
    // @param $dir path where all the parsers are stored
    public function __construct($dir){
    }
    // @returns all the available parsers by scanning files. 
    public function get(){
    }
}

class DataParser{
    public function factory($data){
       $instance = null;
       $pr= new ParserRegistry("/some/path");
       foreach($pr->get() as $pname){
           $rc = new ReflectionClass($pname);
           $instance = $rc->newInstance($data);
           if($instance->can_parse())
               return $instance;
       }
       throw new ParserException("No parser found", 1);
    }
}

適切なファクトリーメソッドの使用法ですか?

私を悩ませていることの1つは、can_parse方法です。テキストを解析できるかどうかをテストするためだけに作成されたパーサーのインスタンスがたくさんあるようです。それを行うより良い方法はありますか?私は静的メソッドを使用できることを知っています。parseしかし、ほとんどのパーサーはメソッドの一部を使用します(AParser定義を参照)。静的にすると、それらのメソッドを使用できなくなります。

注: コード例は、私がフォローしているパターンを表しています。ただし、クラス名とシナリオは単なる例です。この例に既製のソリューションを提供しても、実際の問題は解決しません。

4

2 に答える 2

2

どのパーサー クラスを使用するかを調べるためだけに、すべてのパーサー クラスをインスタンス化 (定義をロード) したくないと自分で書いているので、設計を変更する必要があります。

まず第一に、パーサーに解析だけを行わせ、データの解析とセンシングを行わないようにすることを強くお勧めします。1 つのオブジェクト、つまり 1 つのジョブです。複雑にしないでおく。

データ型スニッフィング (どのパーサーが使用するか) が実際に行うことは、ファクトリ内にあります。これはおそらく、ファクトリ メソッドには少し多めです。インスタンス化する具体的なクラス名を決定する必要がある場合でも、そのためにロジック全体をカプセル化する必要があるという意味ではありません。また、時間の経過とともにパーサーを追加するため、これは時間の経過とともに変化する可能性があります。

したがって、次の改善点はおそらく、ファクトリ メソッドの代わりにファクトリ メソッド オブジェクトを使用することです。つまり、ファクトリをインスタンス化して、時間をかけて新しいファクトリ タイプに置き換えることができます。

これを段階的に行うことができるはずです。

  1. can_parseインターフェイスからメソッドを削除します。パーサーが内部で使用したい場合は、非公開にします。しかし、それは具体的な のインターフェース (抽象として強制される) には属しませんParser
  2. メイクDataParserと現物ParserFactory。インスタンス化して、必要な場所に渡します。factoryメソッドの名前を に変更して、makeParser何が起こっているのかをより明確にします。
  3. そのファクトリ オブジェクトをインターフェイスに変換し、クラスの名前をそのインターフェイスを実装する具体的な名前に変更します。

ParserFactory::makeParser時間の経過とともに、必要に応じてメソッドを再実装できるようになりました。必要な場合は、新しいファクトリ オブジェクトを作成するだけです。それが頻繁に変わる場合は、決定をファクトリにも注入可能にしたいかもしれませんが、私はそのステップを延期します。あなたが今していることは、最善の方法かもしれません。まず、パーサーから移動するだけです。たとえば、潜在的なクラスのリストに対してテストを行いParseExceptions、パーサーがデータを (正常に) 解析できないことを示すシグナルをキャッチします。ソフトウェアの動作を維持し、物事を互いに少し離してください。その後、別の処理を行う 2 番目のファクトリ オブジェクトを作成できます。オブジェクトを変更するだけで済みます。アプリケーションの残りの部分 (つまり、既存のすべてのパーサー) は変更する必要がありません。

これにより、具体的なパーサーをインスタンス化 (作成) する方法を決定するための最良の方法である実験に必要なすべての自由が得られます。

于 2013-03-03T10:58:39.700 に答える
0

一般的に言えば、それは正しいように見えます。Factoryは、入力に基づいてオブジェクトを生成します。can_parse()についてはよくわかりません。特定のオブジェクトに委任するのではなく、工場で決定する必要があると思いました。

こちらをご覧くださいhttp://sourcemaking.com/design_patterns/factory_method

于 2013-03-02T22:18:09.503 に答える