バックエンド

PHPデザインパターン:Decoratorパターンの基礎と実践

デザインパターンはソフトウェア開発における共通の課題を解決するための再利用可能なテンプレートを提供します。その中でもDecoratorパターンは、オブジェクトの動的な振る舞いの拡張に役立つ重要なパターンの1つです。本記事では、DecoratorパターンをPHPで実装する方法と、その実用例を解説します。

Decoratorパターンとは?

Decoratorパターンは、元のオブジェクトに変更を加えずに機能を拡張するためのデザインパターンです。このパターンでは、元のオブジェクトをラップする「デコレーター」クラスを作成することで、追加の責務を動的に付与できます。

特徴

  • オープン/クローズドの原則: 新しい機能を追加する際に既存のコードを変更する必要がありません。
  • 動的拡張: 実行時に機能を追加できます。
  • 柔軟性: 継承よりも柔軟で、複数のデコレーターを組み合わせることが可能です。

Decoratorパターンの構造

以下はDecoratorパターンの一般的な構造です:

  1. コンポーネント (Component): 基本的なインターフェースまたは抽象クラス。
  2. 具体コンポーネント (Concrete Component): 実際の機能を持つクラス。
  3. デコレーター (Decorator): コンポーネントのインターフェースを実装し、元のコンポーネントをラップするクラス。
  4. 具体デコレーター (Concrete Decorator): デコレーターの具体的な拡張を実装したクラス。

PHPでの実装例

1. 基本的な構造

以下は、PHPでのシンプルなDecoratorパターンの例です。

// 1. Componentインターフェース
interface Message
{
    public function getContent(): string;
}

// 2. Concrete Component
class SimpleMessage implements Message
{
    private string $content;

    public function __construct(string $content)
    {
        $this->content = $content;
    }

    public function getContent(): string
    {
        return $this->content;
    }
}

// 3. Base Decorator
class MessageDecorator implements Message
{
    protected Message $message;

    public function __construct(Message $message)
    {
        $this->message = $message;
    }

    public function getContent(): string
    {
        return $this->message->getContent();
    }
}

// 4. Concrete Decorators
class EncryptedMessage extends MessageDecorator
{
    public function getContent(): string
    {
        return base64_encode($this->message->getContent());
    }
}

class UppercaseMessage extends MessageDecorator
{
    public function getContent(): string
    {
        return strtoupper($this->message->getContent());
    }
}

// 使用例
$message = new SimpleMessage("Hello, World!");
$encryptedMessage = new EncryptedMessage($message);
$uppercaseMessage = new UppercaseMessage($encryptedMessage);

echo $message->getContent() . "\n"; // Hello, World!
echo $encryptedMessage->getContent() . "\n"; // SGVsbG8sIFdvcmxkIQ==
echo $uppercaseMessage->getContent() . "\n"; // SGVTBGC8SIFDVYMXKRA==

2. 実践例:ログシステム

ログシステムにDecoratorパターンを適用する例を考えてみましょう。

interface Logger
{
    public function log(string $message): void;
}

class FileLogger implements Logger
{
    public function log(string $message): void
    {
        file_put_contents('log.txt', $message . PHP_EOL, FILE_APPEND);
    }
}

class TimestampLogger extends MessageDecorator
{
    public function log(string $message): void
    {
        $this->message->log("[" . date('Y-m-d H:i:s') . "] " . $message);
    }
}

class ErrorLevelLogger extends MessageDecorator
{
    private string $level;

    public function __construct(Logger $logger, string $level)
    {
        parent::__construct($logger);
        $this->level = $level;
    }

    public function log(string $message): void
    {
        $this->message->log("[{$this->level}] " . $message);
    }
}

$logger = new FileLogger();
$timestampLogger = new TimestampLogger($logger);
$errorLogger = new ErrorLevelLogger($timestampLogger, "ERROR");

$errorLogger->log("An error occurred.");

この例では、ログにタイムスタンプやエラーレベルを簡単に追加できるようになります。

Decoratorパターンを使うべき場合

Decoratorパターンを選択すべき場面は以下の通りです:

  1. 既存のクラスに新しい機能を追加したいが、継承を使用したくない場合
  2. 実行時にオブジェクトの振る舞いを動的に変更する必要がある場合
  3. 機能の組み合わせを柔軟に構成したい場合

まとめ

Decoratorパターンは、動的な機能拡張を可能にし、オープン/クローズドの原則を満たす優れたデザインパターンです。PHPでDecoratorパターンを実装することで、柔軟で保守性の高いコードを実現できます。

具体例を参考に、ぜひプロジェクトで活用してみてください!

-バックエンド
-,