0

私はOOPにかなり慣れておらず、1つのクラス名を使用するのに最適な方法について質問がありますが、渡されたパラメーターに基づいてそのクラスに機能を内部的に追加します。

基本的な話は、2つのパラメーター$moduleと$idを受け取る'item'クラスがあるということです。一部の「モジュール」(すべてではありません)には、「item」クラスにデフォルトで含まれない優れた機能があります。一部のモジュールでは、itemクラスの一部のメソッドも上書きする必要があります。私の目標は、itemクラスの__construct内から'item'クラスのモジュールの拡張機能を呼び出せるようにすることです。ただし、単一の「アイテム」クラスが必要です。

私の最初の考えは、アイテムクラスを構築するときにモジュールのアイテム拡張クラスのインスタンスを作成することです。次に、アイテムクラスのメソッドを呼び出すたびに、そのモジュール固有のインスタンスがあるかどうかを確認し、メソッドを呼び出します。そのインスタンスで。

例えば:

class item {
    // Variable where I'll store the instance of the child class
    var $child;
    // Child class may call up item's constuct, I'll use this to avoid an infinite loop
    var $child_initalized;
    // Child called, guess we have to keep track of this so we don't get stuck in infite loops either.
    var $child_called = 0;
    // Example variables
    var $id, $name;

    function __construct($module,$id) {
        if(!$this->child_initialized) {
            $this->child_initialized = 1; // So we don't do this again and get stuck in an infite loop
            $child_class = __CLASS__.'_'.$module;
            if(class_exists($child_class)) {
                $this->child = new $child_class($module,$id);
                return;
            }
        }

        // do normal class construction stuff here, such as setting $this->id and $this->name
        $this->module = $module;
        $this->id = $id;
    }

    // So we can catch child methods not in parent item class
    function __call($name,$arguments) {
        if($this->child) {
            return $this->child->$name();
        }
    }

    function id() {
        $this->child_called = 0;
        if($this->child) {
            $this->child_called = 1;
            return $this->child->id();
        }
        return $this->id;
    }
}

class item_photos extends item {
    function __construct($module,$id) {
        $this->child_initialized = 1;
        parent::__construct($module,$id);
    }

    function id() {
        return "photo-".$this->id;
    }

    function photo_width() {
        return 250; // Just some sample value
    }
}

$item = new item('photos',123);
print $item->id()."<br />"; // photo-123
print $item->photo_width()."<br />"; // 250

とにかく、それはほんの簡単な例でした。しかし、私の方法は...まあ、間違っているようです。これを達成するためのより良い方法はありますか、それとも私がすべてをどのように構成しているかを再考する必要がありますか?あなたが提供できるアドバイスやアイデアは素晴らしいでしょう。

/ * ** * ** * ****編集**** ** * ** * * / _ _ _ _

明確にするために、私の目標は、実際には1つのクラス(私の例では「item」)を呼び出し、渡された1つ以上のパラメーターに基づいて、それらのパラメーターに基づいてより多くの機能を動的にロードできるようにすることです(私の例では、それは$ moduleです)。ただし、その追加機能が常に存在するとは限りません(したがって、new item()の代わりにnew item_photosを常に呼び出すことはできません)。

これが更新された例です。コードの最後で$item= new item('videos'、456)を呼び出すことは、一部のモジュールに追加機能がない方法の例です。

class item {
    // Variable where I'll store the instance of the child class
    public $child;
    // Child class may call up item's constuct, I'll use this to avoid an infinite loop. Also to avoid when calling child class in methods.
    public $child_initalized;
    // Example variables
    public $module, $id, $name;

    function __construct($module,$id) {
        if(!$this->child_initialized) {
            $child_class = __CLASS__.'_'.$module;
            if(class_exists($child_class)) {
                $this->child = new $child_class($module,$id);
                return;
            }
        }

        // do normal class construction stuff here, such as setting $this->id and $this->name
        $this->module = $module;
        $this->id = $id;
    }

    // So we can catch child methods not in parent item class
    function __call($name,$arguments) {
        if($this->child) {
            return $this->child->$name();
        }
    }

    function id() {
        $this->child_initalized = 0;
        if($this->child) {
            $this->child_initalized = 1;
            return $this->child->id();
        }
        return $this->id;
    }
}

class item_photos extends item {
    function __construct($module,$id) {
        $this->child_initialized = 1;
        parent::__construct($module,$id);
    }

    function id() {
        return "photo-".$this->id;
    }

    function photo_width() {
        return 250; // Just some sample value
    }
}

$item = new item('photos',123);
print "photo id: ".$item->id()."<br />"; // photo-123
print "photo size: ".$item->photo_width()."<br />"; // 250

$item = new item('videos',456);
print "video id: ".$item->id()."<br />"; // 456
print "video size: ".$item->photo_width()."<br />"; // nothing (that method doesn't exist here)

/ * ** * ** ****編集2 *** * ** * *** / _ _

まだ少し苦労しています。抽象ファクトリを調べましたが、機能しないようです。それらを正しく理解していれば、抽象クラスですべてのメソッドを宣言する必要があります。これは、モジュールがアイテムクラスを拡張するため、すべてのメソッドがわからないため、注意が必要です。さらに、避けようとしているのは「item」ではなく、「item_photos」または「item_videos」と呼ばなければならないようです。言うまでもなく、私の例ではitem_videosも存在しません。

1つのクラスを呼び出すという私の目標を考慮して、そのクラス__construct内で、$ moduleに基づいて含める必要のある追加機能があるかどうかを判断し、これを考え出しました。

基本的に、「item」クラスは新しい「item_core」に移動されます。古いアイテムクラスは、モジュールのアイテムクラス(例:item_photos)またはコアアイテムクラス(item_core)のいずれかを使用するクラスを決定するだけです。これらのクラスの1つを初期化した後、インスタンスを保存し、メソッドを呼び出すたびにそれを使用します(__callを介して、__ callを使用するのが悪い理由を教えてください)。

class item {
    // Instance of the core class or module class
    private $instance;

    function __construct($module,$id) {
        $class = __CLASS__;
        $class_core = $class.'_core';
        $class_module = $class.'_'.$module;

        // Module class
        if(class_exists($class_module)) $this->instance = new $class_module($module,$id);

        // Core class
        else $this->instance = new $class_core($module,$id);
    }
    // Catch all calls, redirect accordingly
    function __call($name,$arguments) {
        if($this->instance) {
            if(method_exists($this->instance,$name)) return $this->instance->$name();
        }
    }
}
class item_core {
    public $module, $id;

    function __construct($module,$id) {
        $this->module = $module;
        $this->id = $id;
    }

    function id() {
        return $this->id;
    }
}

class item_photos extends item_core {
    function __construct($module,$id) {
        parent::__construct($module,$id);
    }

    function id() {
        return "photo-".$this->id;
    }

    function photo_width() {
        return 250; // Just some sample value
    }
}

$item = new item('photos',123);
print "photo id: ".$item->id()."<br />"; // photo-123
print "photo size: ".$item->photo_width()."<br />"; // 250

$item = new item('videos',456);
print "video id: ".$item->id()."<br />"; // 456
print "video size: ".$item->photo_width()."<br />"; // nothing (that method doesn't exist in the videos module)

誰かがこれに問題があるか、とにかくそれを改善するために何かを見ますか?それはまだ私には少しずれているようです。

/ * ***編集3** * **** /

了解しました。私がやりたいことは、呼び出したものとは異なるインスタンスを返すことができるようにすることです。したがって、new item($ module、$ id);を呼び出しますが、$ module == photos(私の例では)の場合、new item_photos($ module、$ id);のインスタンスを返したいと思います。これまでのところ、2つの可能な解決策を考え出しました。

最初は、編集2で概説したものです(上記を参照)。

2番目のオプションは、関数(おそらく'item')を呼び出して、そこに正しいオブジェクトインスタンスを返すことです(関数は必要なオブジェクトインスタンスを返すことができますが、クラスコンストラクターは独自のクラスのインスタンスのみを返すため)。だから(基本的な例):

function item($module,$id) {
    $class_module = 'item_'.$module;
    // Module class
    if(class_exists($class_module)) return new $class_module($module,$id);
    // Core class
    else return new item($module,$id);
}
class item{..}
class item_photos{..}

$item = item('photos',123);
print $item->id(); // photo-123

関数/クラスを混合するのが好きかどうかはわかりませんが、それは非常に簡単にトリックを実行します。

考え?

4

3 に答える 3

2

子クラスを内部で作成する代わりに、外部で作成してitemクラスに注入する必要があります(依存性注入は調べたいものです)。コントローラのファクトリを使用してこれを実行することをお勧めします。の使用__callも少し怪しげで、インターフェースを壊します。なぜあなたが抽象化のレベルを必要とするのかわかりませんitem_photos..あなたはそのオブジェクト自体を単に従事させることができます。

于 2012-05-02T00:11:17.410 に答える
2

実装しようとしていることは、ファクトリデザインパターンによって実現できるようです。一言で言えば、このパターンは、一連の構成オプションを渡して、操作するオブジェクトを表すものを取り戻したい場合に適しています。Itemクラスを内部から変更しようとするのではなく、新しいオブジェクトを返すItemFactoryクラスを作成してみませんか。たとえば、工場に写真またはビデオを要求すると、必要なものだけが含まれ、余分なものは何もないPhotoクラスまたはVideoクラス(一般的なItemクラスから拡張されたもの)が返されます。

PHPの例を使用してパターンをより詳細に説明する記事は次のとおりです。http://sourcemaking.com/design_patterns/abstract_factory/php/2

于 2012-05-02T03:47:56.147 に答える
1

私はあなたがそれをすべて間違っていると思います。

クラスを実装したいとしますABそして、いくつかの共通の属性を共有するクラスですが、より多くのA機能を備えています。そして、クラスCなど...

これが私がそれをする方法です:

  • クラスの最小の共通属性を把握する
  • それらを-たとえば-BasicItemクラスとして実装します。(このクラス自体を使用することはできませんが、...「派生」クラスに使用するだけです)
  • A他のすべてのB、、その上にあるクラスをベースにします(継承を使用)。
于 2012-05-02T00:12:02.480 に答える