PHP设计模式 PHP 组合模式

2024-02-26 开发教程 PHP设计模式 匿名 2

目的

以单个对象的方式来对待一组对象

例子

  • form类的实例包含多个子元素,而它也像单个子元素那样响应render()请求,当调用 render() 方法时,它会历遍所有的子元素,调用 render() 方法

UML 图

代码

Renderable.php

<?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Composite;
interface Renderable
{
public function render(): string;
}

Form.php

<?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Composite;
/**
* The composite node MUST extend the component contract. This is mandatory for building
* a tree of components.
*/
class Form implements Renderable
{
/**
* @var Renderable[]
*/
private array $elements;
/**
* runs through all elements and calls render() on them, then returns the complete representation
* of the form.
*
* from the outside, one will not see this and the form will act like a single object instance
*/
public function render(): string
{
$formCode = '<form>';
foreach ($this->elements as $element) {
$formCode .= $element->render();
}
return $formCode . '</form>';
}
public function addElement(Renderable $element)
{
$this->elements[] = $element;
}
}

InputElement.php

<?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Composite;
class InputElement implements Renderable
{
public function render(): string
{
return '<input type="text" />';
}
}

TextElement.php

<?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Composite;
class TextElement implements Renderable
{
public function __construct(private string $text)
{
}
public function render(): string
{
return $this->text;
}
}

测试

Tests/CompositeTest.php

<?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Composite\Tests;
use DesignPatterns\Structural\Composite\Form;
use DesignPatterns\Structural\Composite\TextElement;
use DesignPatterns\Structural\Composite\InputElement;
use PHPUnit\Framework\TestCase;
class CompositeTest extends TestCase
{
public function testRender()
{
$form = new Form();
$form->addElement(new TextElement('Email:'));
$form->addElement(new InputElement());
$embed = new Form();
$embed->addElement(new TextElement('Password:'));
$embed->addElement(new InputElement());
$form->addElement($embed);
// This is just an example, in a real world scenario it is important to remember that web browsers do not
// currently support nested forms
$this->assertSame(
'<form>Email:<input type="text" /><form>Password:<input type="text" /></form></form>',
$form->render()
);
}
}