模式概念
组合模式:将对象组合成树形结构,以表示“部分-整体”的层次结构;
独立对象:一个有特定功能的对象,它不引用任何其他对象;
组合对象-则是提供相似功能对象的集合,管理独立对象。并为客户端提供和独立对象一样的访问方式。
应用场景
- 想表示对象的部分-整体层次结构;
- 让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节
UML类图
代码实现
** RenderableInterface.php**
<?php
namespace DesignPatterns\Structural\Composite;
interface RenderableInterface
{
public function render(): string;
}
Form.php
<?php
namespace DesignPatterns\Structural\Composite;
/**
* The composite node MUST extend the component contract. This is mandatory for building
* a tree of components.
*/
class Form implements RenderableInterface
{
/**
* @var RenderableInterface[]
*/
private $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
*
* @return string
*/
public function render(): string
{
$formCode = '<form>';
foreach ($this->elements as $element) {
$formCode .= $element->render();
}
$formCode .= '</form>';
return $formCode;
}
/**
* @param RenderableInterface $element
*/
public function addElement(RenderableInterface $element)
{
$this->elements[] = $element;
}
}
InputElement.php
<?php
namespace DesignPatterns\Structural\Composite;
class InputElement implements RenderableInterface
{
public function render(): string
{
return '<input type="text" />';
}
}
TextElement.php
<?php
namespace DesignPatterns\Structural\Composite;
class TextElement implements RenderableInterface
{
/**
* @var string
*/
private $text;
public function __construct(string $text)
{
$this->text = $text;
}
public function render(): string
{
return $this->text;
}
}
CompositeTest.php
<?php
namespace DesignPatterns\Structural\Composite\Tests;
use DesignPatterns\Structural\Composite;
use PHPUnit\Framework\TestCase;
class CompositeTest extends TestCase
{
public function testRender()
{
$form = new Composite\Form();
$form->addElement(new Composite\TextElement('Email:'));
$form->addElement(new Composite\InputElement());
$embed = new Composite\Form();
$embed->addElement(new Composite\TextElement('Password:'));
$embed->addElement(new Composite\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->assertEquals(
'<form>Email:<input type="text" /><form>Password:<input type="text" /></form></form>',
$form->render()
);
}
}
心得总结
- “部分-整体”的结构层次,而部分和整体又有统一的接口;
- 层次结构清晰,客户针对抽象进行编程,无需知道是代表部分的叶子对象 还是 代表整理的容器对象,一直的调用方式;