web-dev-qa-db-ja.com

PHPでコンポジションを実装する方法

PHPを使用して、ダイアグラムの次のフラグメントを実装したいと思います。

構成例 以下の図を参照してください。

enter image description here

内部クラスを使用して、Javaでコンポジションを実装できます。

しかし、PHPには「内部クラス」の類似物はありません。もちろん、特徴はあります。ただし、複数のクラスで使用できます。

私は次のような構成を実装しました:

class Head {
    private static $instance = NULL;

    private function __construct(){}

    public static function getInstance() {
        $traces = debug_backtrace();
        if (strcmp($traces[1]['class'], 'Human')) {
            echo "<br>Only human has head"; // Exception can be thrown here
            return NULL;
        }
        if (!static::$instance) static::$instance = new self();
        return static::$instance;
    }

    public function __toString() {
        return 'Head';
    }
}

class Human {
    private $head;

    public function __construct() {
        $this->head = Head::getInstance();
    }

    public function __toString() {
        return 'I have ' . $this->head;
    }
}

class Plant {
    private $head;

    public function __construct() {
        $this->head = Head::getInstance();
    }
}

$human = new Human();
echo $human;

$superman = new Plant();

そうするのは正しいですか?

PHPでコンポジションリレーションシップを実装するためのより良い方法はありますか?

10
profport

あなたは本当に OOPの「構成」が何であるかについて混乱しているようです。

コンポジションは2つのクラス間の関連付けであり、インスタンス化される最初のクラスのインスタンスでは、2番目のクラスを提供する必要があります。 Humanが存在する特定の図では、Headが必要です。コードでは次のようになります。

_class Head {
}

class Human {
    private $head;
    public function __construct(Head $head) {
       $this->head = $head;
    }
}

$bob = new Human(new Head);
_

以上です。 debug_backtrace()およびシングルトンなしアンチパターンは必要ありません。そして、ところで、これはJavaでも、内部クラスを持つオプションがあっても、ほぼ同じように見えます。

投稿したコードは。これは間違っているでしょう:

_if (strcmp($traces[1]['class'], 'Human')) {
    echo "<br>Only human has head"; // Exception can be thrown here
    return NULL;
}
_

この図は、人間だけが頭を持っているとは言っていません。その人間だけ持っている必要がありますインスタンス化される頭。 $skipper = new Dog(new Head);を使用することもできます。これは完全に問題ありません。

27
tereško

継承をめぐる構成。

基本的に、compositionは、aggregationのより強力な形式です。頭なしでは生きていけないので、体と頭の関係は構成であると言えますが、手を失う可能性があるので、体と手の関係は集合体であり、生き続けることができます。 直接関連付け一時的な関連付けのような弱い関係もあります。

ただし、依存性注入は、(あるクラスを別のクラスに注入することによって)それらの関連付けを作成するパターンにすぎません。

ほとんどの場合、別のオブジェクトを注入してそのプロパティに割り当てるコンストラクターによって構成関係を認識でき、オブジェクトのライフサイクルは同じ瞬間に終了および開始します。

それ以外は、技術的な観点からは、各協会の実施に大きな違いはありません。これは主に、実装ではなく関係の定義の問題です。

合成関係は、注入されたオブジェクトクラスの動作を上書き/変更または強化するためによく使用されます。構図に興奮したり心配したりしないでください。ほとんどの場合、継承に対する利点は小さく、コンポジションを使用してライブラリに柔軟性を追加するサードパーティのライブラリ作成者が最も楽しんでいます。

親クラスから継承し、メソッドをオーバーロード/追加すると、同様の機能が得られますが、構成を使用すると、柔軟性が向上します。たとえば、コンストラクターがHeadインターフェイスから継承するオブジェクトを受け入れる場合、Headインターフェイスを拡張する場合はHumanHeadクラスを使用できますが、DogHeadやDuckHeadなどの同じインターフェイスから拡張する他のクリーチャーを拡張するためにクラスを使用することもできます。

これはおそらく最良の例ではありませんが、基本的な概念を示しています。

必ずこれをチェックしてください [アグリゲーションvsコンポジションvsアソシエーションvsダイレクトアソシエーション] そしてこれ [アソシエーション-アグリゲーション-コンポジション-ディペンデンシー]

4
DevWL

コンポジションは2つのクラス間の関連付けであり、インスタンス化される最初のクラスのインスタンスでは、2番目のクラスを提供する必要があります。人間が存在するための特定の図では、頭が必要です。以下の例を参照してください。理解を深めるために、上記の例を使用します。

public function test()
{
    return "I am foo";
}

class Human 
{
    public $head;

    public function __construct(Head $head)
    {
        $this->head = $head;
    }

    public function display() 
    {
        return $this->head->test();
    }
}

$obj = new Human(new Head);

echo $obj->display();
0