2.3. Composite

2.3.1. Zweck

Eine Gruppe von Objekten genauso zu behandeln wie eine einzelne Instanz eines Objekts.

2.3.2. Beispiele

  • Eine Formular-Klasseninstanz behandelt alle seine beinhalteten Formelemente wie eine eine einzelne Instanz des Formulars. Wenn render() aufgerufen wird, werden alle Kindelemente durchlaufen und auf jedem wieder render() aufgerufen.

2.3.3. UML Diagramm

Alt Composite UML Diagram

2.3.4. Code

Du findest den Code auch auf GitHub

Renderable.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7interface Renderable
 8{
 9    public function render(): string;
10}

Form.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7/**
 8 * The composite node MUST extend the component contract. This is mandatory for building
 9 * a tree of components.
10 */
11class Form implements Renderable
12{
13    /**
14     * @var Renderable[]
15     */
16    private array $elements;
17
18    /**
19     * runs through all elements and calls render() on them, then returns the complete representation
20     * of the form.
21     *
22     * from the outside, one will not see this and the form will act like a single object instance
23     */
24    public function render(): string
25    {
26        $formCode = '<form>';
27
28        foreach ($this->elements as $element) {
29            $formCode .= $element->render();
30        }
31
32        return $formCode . '</form>';
33    }
34
35    public function addElement(Renderable $element)
36    {
37        $this->elements[] = $element;
38    }
39}

InputElement.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7class InputElement implements Renderable
 8{
 9    public function render(): string
10    {
11        return '<input type="text" />';
12    }
13}

TextElement.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite;
 6
 7class TextElement implements Renderable
 8{
 9    public function __construct(private string $text)
10    {
11    }
12
13    public function render(): string
14    {
15        return $this->text;
16    }
17}

2.3.5. Теst

Tests/CompositeTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Composite\Tests;
 6
 7use DesignPatterns\Structural\Composite\Form;
 8use DesignPatterns\Structural\Composite\TextElement;
 9use DesignPatterns\Structural\Composite\InputElement;
10use PHPUnit\Framework\TestCase;
11
12class CompositeTest extends TestCase
13{
14    public function testRender()
15    {
16        $form = new Form();
17        $form->addElement(new TextElement('Email:'));
18        $form->addElement(new InputElement());
19        $embed = new Form();
20        $embed->addElement(new TextElement('Password:'));
21        $embed->addElement(new InputElement());
22        $form->addElement($embed);
23
24        // This is just an example, in a real world scenario it is important to remember that web browsers do not
25        // currently support nested forms
26
27        $this->assertSame(
28            '<form>Email:<input type="text" /><form>Password:<input type="text" /></form></form>',
29            $form->render()
30        );
31    }
32}