2011-12-09 2 views
4

私はその後PageクラスもContentAbstractPHPデザインパターン:他の人に拡張させるクラスではプライベートコンストラクタが悪いですか?

class Page extends ContentAbstract 
{ 
    protected static $type = 'Page'; 

    private $template_file; 
    private $short_name; 

    static function newFromName($name) 
    { 
    $data = get_content_id_from_page_table_using_the_short_name($name); 
    $page = new Page($data['id']); 
    $page->template_file = $data['template_file']; 
    ... 
    } 

    static function newFromID($id) 
    { 
    $data = get_content_id_from_page_table_using_the_ID($id); 
    $page = new Page($data['id']); 
    $page->template_file = $data['template_file']; 
    ... 
    } 
} 

のサブクラスであるこの

abstract class ContentAbstract 
{ 
    protected static $type; 
    protected $id; 
    protected $title; 
    protected $description; 

    protected $page; 
    protected $section; 
    ... 

    function __construct($id = NULL, Page $page = NULL, Section $section = NULL) 
    { 
    if($id != NULL) 
    { 
     $data = get_data_from_content_table_by_id($id); 

     if($data['type'] == static::$type) 
     { 
     initialize_fields_with_data($data); 

     $this->page = fetch_page_object_from_registry($data['page_id']); 
     $this->section = fetch_section_object_from_registry($data['section_id']); 
     } 
     else 
     throw new IncompatibleContentTypeException('Foo'); 
    } 
    else if($page != NULL && $section != NULL) 
    { 
     $this->page = $page; 
     $this->section = $section; 
    } 
    else 
     throw new OphanContentException('Foo'); 
    } 
} 

のようになりますContentAbstractと呼ばれる抽象クラスを持っている今、私の問題はPageコンストラクタがあるという事実にあります一般ユーザーとユーザーはこれを行うことができます:

$page = new Page($valid_page_id); 

Page::newFromName()およびPage::newFromID()の外部で呼び出されたため、ContentAbstract::__construct()を呼び出すことになりましたが、ページ自体のデータ(template_fileおよびshort_name)を初期化できませんでした。だから私は半分のコンテンツデータで終わる。 1つの解決策は、親コンストラクタをPage::newFromID()に似たものでオーバーライドし、Pageがインスタンス化されたときに(もちろん、親コンストラクタをPage::__construct()の中で呼び出すことによって)すべてのフィールドを設定できるようにすることです。

この問題は、short_name列を使用してページのコンテンツIDを取得することと、ページのコンストラクタが呼び出されたときに2つのクエリを作成する必要があるため、Page::newFromName()メソッドにあります。 Page::newFromName()と入力すると、ページに関連付けられたデータを取得するための新しいクエリが作成されます。それは望ましくないですね。

私が見る唯一の解決策は、Page::__construct()を非公開にして、エンドユーザーにオブジェクトをインスタンス化する静的メソッドを使用させることです。

私はオープンソースプロジェクトとしてリリースしたいと考えています。ユーザーはContentAbstractクラスをサブクラス化するだけで、より多くの種類のコンテンツを追加できます。個人的なコンストラクタが上記の目的に有害であることを要求しているか(人間の誤りとドキュメンテーションを読むための怠惰を説明する)?あるいは、そのようなことが私の懸念事項の中で最も少ないのでしょうか?あるいは、実際のクラスそのものの構造自体がこの問題に役立っていますか?

+0

Ahhhh ...しかし、クラスそのものからコンストラクタが呼び出されたかどうかはどのようにわかりますか? –

+0

私はあなたがしたいことを誤って読んでいたので、私の提案は間違っていました。誰かを混乱させないように、私はその問題に関する私のコメントを削除しました! – rdlowrey

答えて

0

「:

$ページ=新しいページ($ valid_page_id)今、私の問題は、ページのコンストラクタが公開され、ユーザーがこれを行うことができるという事実です。」

あなたがOPに投稿したコードによると、これは当てはまりません。あなたのページは、コンストラクトが存在するところでContentAbstractを拡張しますが、実際にはPageクラスからconstructを呼び出すわけではありません。

class Page extends Content // I wouldn't name this abstract as it may change in the future 
{ 
    public function __construct($args) 
    { 
     // Here I forced a call to parent 
     // If I comment this out, the parent construct will never be accessed 
     parent::__construct($args); 
    } 
} 
+0

はい、問題は、 'Page'コンストラクタもpublicになるように親コンストラクタをオーバーライドしたことがないことです。したがって、 'new Page($ id)'で有効なIDを渡す限り、スクリプトは不平を言うことはありません。ただし、ページのプロパティの初期化はすべて静的メソッドで行われるため、継承されたプロパティだけがそのように設定されます。 –

+0

@RolandoCruz:もちろん、ああ。あなたのようなコンストラクトを実装すると、私は常にそれをオーバーライドします。 –

+0

@RolandoCruz:ちょっと考えましたが、ContentAbstract :: __ construct()の内容を 'protected init()'メソッドに移動させるのはどうですか?この方法では、インスタンス化時にコードに直接アクセスすることはできませんが、静的メソッドでもメンバー変数を初期化できますか? –

関連する問題