2011-10-06 2 views
6

Webページから階層データを掻き集めてDBに保存するように設計されたPHPプロジェクトをよくします(基本的にはデータを構造化しますデータは構造化された方法で提供しません)。たびに、私は私が次のことを達成できるようになるOOPのデザインを思い付くしよう:PHP OOPデザイン - ジェネリックインターフェイスを実装しながら特定の子クラスにパラメータを限定する

  • オリジナルのウェブページはの簡単な拡張を許可する
  • を変更する場合には簡単に、新しいものにスクリプトを解析現在のHTMLを置き換えますこれらのプロジェクトは他の人が取ってビルドするためのものであるため、データは削り取られて保存されます。私の目的は「基本」データを収集することですが、他の人は余分なものを含めることを決めるかもしれませんが、保存方法などを変更することがあります。

これまでのところ、このようなことは何か:

が、私は一般的なツリートラバース機能を実装し、データコンテナのための抽象クラスを定義します。

abstract class DataContainer { 

    protected $parent = NULL; 
    protected $children = NULL; 

    public function getParent() { 
    return $this->parent; 
    } 

    public function getChildren() { 
    return $this->children; 
    }    
} 

そして私は、実際のデータコンテナを持っています。想像してみると、私は、議会のセッションへの参加に関するデータを「座っている特定の質問」レベルまで掘り下げています。私はSessionContainerSittingContainerQuestionContainerを持っていて、それらはすべてDataContainerになります。

各セッション、座っているデータおよび質問データは、別のURLからスクレイプされています。 URLコンテンツを取り除くメカニズムを残して、実際に解析するためにコンテナとDOmDocumentを取るスクレイパークラスが必要だとしましょう。 、そして、セッションのそれぞれを

interface Scraper { 
    public function scrapeData(DOMDocument $Dom, DataContainer $DataContainer); 
} 

座っての質問は、インターフェイスを実装し、独自のスクレーパーを持っているでしょう。だから私は、このような一般的なインタフェースを定義します。しかし、私は彼らが意味するコンテナだけを受け入れることもできるようにしたいと思います。だから、それは次のようになります。

class SessionScraper implements Scraper { 
    public function scrapeData(DOMDocument $DOM, SessionContainer $DataContainer) { 
    } 
} 

最後に、私はまた、スクレーパーインタフェースを実装し、ちょうど関連のスクレーパーにスクレイピングを配布し、一般的なFactoryクラスを持っているでしょう。このように:

public function scrapeData(DOMDocument $DOM, DataContainer $DataContainer) { 
    //get the scraper from configuration array 
    $class = $this->config[get_class($DataContainer)]; 
    $craper = new $class(); 
    $class->scrapeData($DOM, $DataContainer); 
} 

これは実際にコードで呼び出されるクラスです。同様に、DBに保存することもできます。各データコンテナはDBSaverインターフェイスを実装するDBSaverクラスを持つことができます。ここでも、すべての呼び出しはFactoryクラスを介して実行できます。これはDBSaverインターフェイスも実装します。

すべてが完璧ですが、問題はインターフェイスを実装するクラスがインターフェイスの正確な署名を実装する必要があることです。例えば。メソッドSessionScraper::scrapeDataのみ受け入れることができませんSessionContainerオブジェクトはすべてDataContainerオブジェクトを受け入れる必要があります。しかしそれは意味がありません!最後に

、質問:

  • は私の設計が間違っていると私は完全に別の方法ですべてを構築すべきですか? (どうやって?)、または:
  • 私のデザインはOKです。タイプヒントではなく、instanceofと同様のチェックを使ってメソッド内で型を強制する必要がありますか?

すべての提案/批評に感謝します。私は、必要に応じて、このコードを頭の中で覆す人に完全に満足しています!

答えて

2

Containerが目に触れます。この名前は非常に一般的なものなので、もっと動的なものが必要な場合があります。私はあなたがDataとあなたはclassifyそれを持っていると思うので、それはtypeを持っています。

正確なインターフェイスをタイプヒントにハードコードする代わりに、これを動的に解決する必要があります。今、各Containertypeを持っている希望の場合

は、Scraper信号/それはContainertypeに適用可能であるかどうかを言うことができます。

スクレイピングの具体的な形は、実際にあなたがそれを解析するために、特定のデータに使用戦略です。あなたのコンテナこの戦略をカプセル化し、正規化されたデータへのインタフェースを提供します。

ContainerScraperの間にロジック/契約を追加するだけで、お互いに話すことができます。この契約は、両方のインターフェースの内側に置くことができます。

これにより、伸ばしたい場合はtypesを複数扱えるScraperにすることもできます。

Containerについては、イテレーター(および再帰イテレーター)を使用できるようにいくつかのインターフェースを実装するだけでなく、SPLも見てください。これはあなたが参照している一般的な構造かもしれませんし、SPLはあなたのContainerクラスのユーザビリティを高めることができます。

OOPのすべてをハードコードする必要はありません。動的に、特にPHPでは通常は実行時に問題を解決します。

Scrapersを新しいバージョンに簡単に置き換えることもできます。 Scrapersは、(前述のように)定義によって型を持つため、実行時に具体的なクラスがスクラップを実行する必要があります。 .phpファイルから素敵なファイルシステム構造で動的にロードします。

ちょうど私の2セントです。

+0

広範な回答をいただきありがとうございます - 他にもいくつかのアイデアを引き起こしました。 1つの説明 - すべてのデータを保持するための1つのデータ/コンテナクラスを持ち、子クラスを作成するのではなくタイププロパティで識別することを基本的にお勧めしていることを正しく理解していますか?または、両方のタイプのプロパティと子クラスになりますが、スクレイパーは型だけを考慮に入れますか? – Aurimas

+0

あなたのデータは特に分かりませんので、わかりにくいです。データが非常に共通する場合は、プロパティが異なるだけで、多くのデータクラスを作成する必要はなく、動的プロパティを使用することもできます。後で全体的なアプリケーションの方がはるかに優れています。ほとんどの場合、スクレーパーは変更され、時にはデータが変更されます。いくつかのウェブサイトが少し変更されただけなので、常に新しいデータクラスを作成する必要があります。良くない :) – hakre

関連する問題