PHP 设计模式之组合模式

PHP设计模式之组合模式 Composite

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以
及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

  1. 使用过 laravel-admin 这个快速后台的同学,应该都使用过它的表单类 Form 创建表单的时候,只需要 new Form,然后添加对应的输出的表单
    元素就可以了,很快捷,很方便,其实它就是使用了 组合模式

  2. 根据以上的例子,首先需要定义一个输出的元素(组合元素)的接口 Renderable它里面也之定义了一个方法 render():string类型的返回参数

interface Renderable
{
    public function render():string;
}
  1. 创建一个根元素Form类,实现接口 Renderable,在render(): string这个方法中,需要返回已经组建好的完整表单元素,在这个方法中我们稍微
    做一下改进,我们需要定义两个成员变量,都是数组,一个是我们事先定义好的表单元素数组类,提供给我们最后调用表单方法的时候使用,还有一个提前定义
    好的空数组,这个是我们最后组件完整表单的时候使用。最后再写一个魔术方法,调用我们的具体表单元素。
class Form implements Renderable
{
    private $action = './index.php';

    private $method = 'get';

    protected $elements = [
        'text' => Text::class,
        'email' => Email::class,
        'password' => Password::class,
        'file' => File::class,
        'radio' => Radio::class,
        'number' => Number::class,
        'hidden' => Hidden::class,
    ];

    protected $items = [];

    public function addElements(string $formName, Renderable $renderable)
    {
        if (!isset($this->elements[$formName])) {
            $this->elements[$formName] = $renderable;
        }
    }

    public function setAction(string $action)
    {
        $this->action = $action;

        return $this;
    }

    public function getAction()
    {
        return $this->action;
    }

    public function setMethod(string $method)
    {
        $this->method = $method;

        return $this;
    }

    public function getMethod()
    {
        return $this->method;
    }

    public function render(): string
    {
        // TODO: Implement render() method.
        $formString = <<<ERT
<form action="{$this->getAction()}" method="{$this->getMethod()}">
ERT;

        foreach ($this->items as $item) {
            $formString .= $item;
        }

        $formString .= <<<TRE
</form>
TRE;

        return $formString;

    }

    public function pushField(string $fields)
    {
        $this->items[] = $fields;

        return $this;
    }

    public function __call($name, $arguments)
    {
        // TODO: Implement __call() method.
        if (!isset($this->elements[$name])) {
            $message = sprintf('this is method %s not exists!', $name);
            throw new RunException($message);
        }

        $class = $this->elements[$name];

        $class = new $class;

        if (is_array($arguments)) {
            $field = $arguments[0];
        } else {
            $field = (string) mt_rand(100, 999);
        }

        $formText = $class->setField($field)->render();

        $this->pushField($formText);

        return $this;
    }
}
  1. 创建一些表单元素,也需要实现接口 Renderable,在各自的render(): string方法中,返回当前创建的子表单,比如这里列举创建的text, email, password
class Email extends Field  implements Renderable
{

    public function render(): string
    {
        // TODO: Implement render() method.
        return <<<ERT
<div class="form-group">
    <label for="{$this->getFiled()}">{$this->getFiled()}</label>
    <input type="email" name="{$this->getFiled()}">
</div>
ERT;
    }
}

class Text extends Field implements Renderable
{
    public function render(): string
    {
        // TODO: Implement render() method.
        return <<<ERT
<div class="form-group">
    <label for="{$this->getFiled()}">{$this->getFiled()}</label>
    <input type="text" id="{$this->getFiled()}" name="{$this->getFiled()}">
</div>
ERT;
    }
}

class Password extends Field implements Renderable
{

    public function render(): string
    {
        // TODO: Implement render() method.
        return <<<ERT
<div class="form-group">
    <label for="{$this->getFiled()}">{$this->getFiled()}</label>
    <input type="password" name="{$this->getFiled()}">
</div>
ERT;
    }
}
  1. 测试,我们首先new Form()类,然后添加正常的表单元素,最后输出到页面上,得到一个完整的表单
require '../vendor/autoload.php';

use Composite\Form;
//http://local.test.abc/
$form = new Form();

$form->text('username');

$form->password('password');

$form->email('email');
$form->number('number');
$form->file('file');
$form->hidden('hidden');

$style = <<<ERT
<style>
.form-group {
padding-bottom: 20px;
}
</style>
ERT;

echo $style;
echo $form->render();

/**
* <form action="./index.php" method="get"><div class="form-group">
      <label for="username">username</label>
      <input type="text" id="username" name="username">
  </div><div class="form-group">
      <label for="password">password</label>
      <input type="password" name="password">
  </div><div class="form-group">
      <label for="email">email</label>
      <input type="email" name="email">
  </div><div class="form-group">
      <label for="number">number</label>
      <input type="number" name="number">
  </div><div class="form-group">
      <label for="file">file</label>
      <input type="email" name="file">
  </div><div class="form-group">
      <input type="hidden" name="hidden">
  </div></form>
 */
php
本作品采用《CC 协议》,转载必须注明作者和本文链接
LIYi ---- github地址
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!