【PHPデザインパターン】13_Decorator~かぶせて機能UP
引用記事
この記事を書くきっかけになったブログです。
記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。
Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Decorator~かぶせて機能UP
概要
- Decoratorとは直訳すると「装飾者」。
- オブジェクトに対して機能を柔軟に(動的に)追加したり取り外したりする。
- サブクラス化よりも柔軟な拡張方法を提供する。
- 継承による拡張は責任(機能)を「静的」に追加する。「動的」な追加は、実行中に責任を追加したり外したりできる。
構成要素
Componentクラス
- 拡張される機能を定義した抽象クラス。
ConcreteComponentクラス
- Componentクラスで定義した機能を基本実装する、飾り付けされる具象クラス。
Decoratorクラス
- Componentクラスを実装し、さらにプロパティ(メンバ変数)としてComponentクラスのオブジェクトを保持する抽象クラス。
- メソッドの具体的な実装はComponentクラス(ConcreteComponentクラス)へ委譲する。
ConcreteDecoratorクラス
- Componentクラスに機能を追加するために、Decoratorクラスを継承するクラス。
- 自身のメソッドで親クラスのメソッドを利用しながら機能の拡張(飾り付け)を行う。
実演
処理の流れ
-
PlainTextクラス
で文字列をプロパティとして保有する。
-
TextDecoratorクラス
でTextDataクラス
のオブジェクトを保有する。
-
DoubleTextクラス
で文字列を全角に変換する。
-
UpperTextクラス
で文字列を大文字に変換する。
- TextDataクラスのオブジェクトに対し、再帰処理で各ConcreteDecoratorクラスのメソッドを実行する。
ファイル構造
MyDecorator
├── DoubleText.php
├── PlainText.php
├── TextData.php
├── TextDecorator.php
├── UpperText.php
└── my_client.php
ソースコード
Componentクラス
TextData.php
TextData.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
/**
* Componentクラスに相当する
* インターフェイスのため、サブクラスで実装する
*/
interface TextData
{
public function getText();
public function setText($str);
}
ConcreteComponentクラス
PlainText.php
PlainText.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* ConcreteComponentクラスに相当する
* 編集前のテキストを表すクラス
*/
class PlainText implements TextData
{
private $textString = null;
// 文字列を取得する
// 常にplainの状態で返す
public function getText()
{
return $this->textString;
}
// 文字列をセットする
public function setText($str)
{
$this->textString = $str;
}
}
Decoratorクラス
TextDecorator.php
TextDecorator.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* Decoratorクラス
* TextDataクラスのオブジェクトをプロパティ(メンバ変数)として保有する
*/
abstract class TextDecorator implements TextData
{
// TextDataインスタンスを保有する
private $text;
public function __construct(TextData $target)
{
$this->text = $target;
}
// 一番深い階層に存在するPlainTextクラスで保有する文字列が返される
// 再帰処理を行っている
// getTextメソッドの戻り値に対して、さらにgetTextメソッドを実行している
public function getText()
{
return $this->text->getText();
}
// TextDataインスタンスに文字列をセットする
public function setText($str)
{
$this->text->setText($str);
}
}
ConcreteDecoratorクラス
DoubleText.php
DoubleText.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* ConcreteDecoratorクラスに相当する
* TextDecoratorクラスを継承する
*/
class DoubleText extends TextDecorator
{
// インスタンスをセットする
public function __construct(TextData $target)
{
// 親クラスのメソッド
parent::__construct($target);
}
// 文字列を全角文字に変換して返す
public function getText()
{
// 親クラスのメソッド
$str = parent::getText();
// 文字列を変換する
$str = mb_convert_kana($str, "R");
return $str;
}
}
UpperText.php
UpperText.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* ConcreteDecoratorクラスに相当する
* TextDecoratorクラスを継承する
*/
class UpperText extends TextDecorator
{
// インスタンスをセットする
public function __construct(TextData $target)
{
// 親クラスのメソッド
parent::__construct($target);
}
// 文字列を大文字に変換して返す
public function getText()
{
// 親クラスのメソッド
$str = parent::getText();
// 文字列を変換する
$str = mb_strtoupper($str);
return $str;
}
}
Clientクラス
my_client.php
my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
require dirname(dirname(__DIR__)).'/vendor/autoload.php';
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\DoubleText;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\UpperText;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\PlainText;
function decorate($text, array $decorate = [])
{
$text_object = new PlainText();
// plainの文字列がセットされる
$text_object->setText($text);
// $text_objectは階層のようになる
foreach ($decorate as $val) {
switch ($val) {
case 'double' :
$text_object = new DoubleText($text_object);
break;
case 'upper':
$text_object = new UpperText($text_object);
break;
}
}
// PlainTextクラスが装飾されている状態
// echo '<pre>';
// var_dump($text_object);
// echo '</pre>';
// 最後に追加したクラスが表示される
// var_dump(get_class($text_object));
// 各クラスのオブジェクトのメソッドを実行できる
echo $text_object->getText().'<br>'."\n";
}
$text = 'Hello, World!';
echo '---plain---'.'<br>'."\n";
decorate($text);
echo '---double---'.'<br>'."\n";
decorate($text, ['double']);
echo '---upper---'.'<br>'."\n";
decorate($text, ['upper']);
// upper,double,plainの順で呼び出される
// 再帰処理が実行されているため、実質はplain, double, upperの順番になる
echo '---double + upper---'.'<br>'."\n";
decorate($text, ['double', 'upper']);
処理の流れ
-
PlainTextクラス
で文字列をプロパティとして保有する。 -
TextDecoratorクラス
でTextDataクラス
のオブジェクトを保有する。 -
DoubleTextクラス
で文字列を全角に変換する。 -
UpperTextクラス
で文字列を大文字に変換する。 - TextDataクラスのオブジェクトに対し、再帰処理で各ConcreteDecoratorクラスのメソッドを実行する。
ファイル構造
MyDecorator
├── DoubleText.php
├── PlainText.php
├── TextData.php
├── TextDecorator.php
├── UpperText.php
└── my_client.php
ソースコード
Componentクラス
TextData.php
TextData.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
/**
* Componentクラスに相当する
* インターフェイスのため、サブクラスで実装する
*/
interface TextData
{
public function getText();
public function setText($str);
}
ConcreteComponentクラス
PlainText.php
PlainText.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* ConcreteComponentクラスに相当する
* 編集前のテキストを表すクラス
*/
class PlainText implements TextData
{
private $textString = null;
// 文字列を取得する
// 常にplainの状態で返す
public function getText()
{
return $this->textString;
}
// 文字列をセットする
public function setText($str)
{
$this->textString = $str;
}
}
Decoratorクラス
TextDecorator.php
TextDecorator.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* Decoratorクラス
* TextDataクラスのオブジェクトをプロパティ(メンバ変数)として保有する
*/
abstract class TextDecorator implements TextData
{
// TextDataインスタンスを保有する
private $text;
public function __construct(TextData $target)
{
$this->text = $target;
}
// 一番深い階層に存在するPlainTextクラスで保有する文字列が返される
// 再帰処理を行っている
// getTextメソッドの戻り値に対して、さらにgetTextメソッドを実行している
public function getText()
{
return $this->text->getText();
}
// TextDataインスタンスに文字列をセットする
public function setText($str)
{
$this->text->setText($str);
}
}
ConcreteDecoratorクラス
DoubleText.php
DoubleText.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* ConcreteDecoratorクラスに相当する
* TextDecoratorクラスを継承する
*/
class DoubleText extends TextDecorator
{
// インスタンスをセットする
public function __construct(TextData $target)
{
// 親クラスのメソッド
parent::__construct($target);
}
// 文字列を全角文字に変換して返す
public function getText()
{
// 親クラスのメソッド
$str = parent::getText();
// 文字列を変換する
$str = mb_convert_kana($str, "R");
return $str;
}
}
UpperText.php
UpperText.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextDecorator;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\TextData;
/**
* ConcreteDecoratorクラスに相当する
* TextDecoratorクラスを継承する
*/
class UpperText extends TextDecorator
{
// インスタンスをセットする
public function __construct(TextData $target)
{
// 親クラスのメソッド
parent::__construct($target);
}
// 文字列を大文字に変換して返す
public function getText()
{
// 親クラスのメソッド
$str = parent::getText();
// 文字列を変換する
$str = mb_strtoupper($str);
return $str;
}
}
Clientクラス
my_client.php
my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Decorator\MyDecorator;
require dirname(dirname(__DIR__)).'/vendor/autoload.php';
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\DoubleText;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\UpperText;
use DoYouPhp\PhpDesignPattern\Decorator\MyDecorator\PlainText;
function decorate($text, array $decorate = [])
{
$text_object = new PlainText();
// plainの文字列がセットされる
$text_object->setText($text);
// $text_objectは階層のようになる
foreach ($decorate as $val) {
switch ($val) {
case 'double' :
$text_object = new DoubleText($text_object);
break;
case 'upper':
$text_object = new UpperText($text_object);
break;
}
}
// PlainTextクラスが装飾されている状態
// echo '<pre>';
// var_dump($text_object);
// echo '</pre>';
// 最後に追加したクラスが表示される
// var_dump(get_class($text_object));
// 各クラスのオブジェクトのメソッドを実行できる
echo $text_object->getText().'<br>'."\n";
}
$text = 'Hello, World!';
echo '---plain---'.'<br>'."\n";
decorate($text);
echo '---double---'.'<br>'."\n";
decorate($text, ['double']);
echo '---upper---'.'<br>'."\n";
decorate($text, ['upper']);
// upper,double,plainの順で呼び出される
// 再帰処理が実行されているため、実質はplain, double, upperの順番になる
echo '---double + upper---'.'<br>'."\n";
decorate($text, ['double', 'upper']);
Author And Source
この問題について(【PHPデザインパターン】13_Decorator~かぶせて機能UP), 我々は、より多くの情報をここで見つけました https://qiita.com/yukibe/items/14731a84bc3cf12b86bf著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .