【PHPデザインパターン】16_Mediator～すべては相談役が知っている

# 引用記事
この記事を書くきっかけになったブログです。

記事内の解説やソースコードは、こちらのブログと著者の公開リポジトリを参考にしています。

> [Do You PHP はてな〜[doyouphp][phpdp]PHPによるデザインパターン入門 - Mediator～すべては相談役が知っている](http://d.hatena.ne.jp/shimooka/20141217/1418788236)

# 概要
- 「mediator」とは「仲介者」「調停者」という意味。
- 関連しあうクラス群のやり取りを1つのオブジェクトに集約させる。
- 仲介者とクラスの関係を一対多にし、仲介者のクラスだけを知っていれば、他のクラスを知らなくてもお互いにやり取りできるようにする。
- クラス同士のやり取りを一極集中させ、他のクラスとの結びつきをゆるくして互いに独立性を持たせる。

## 構成要素
### Mediatorクラス
- 仲介者のクラス。
- Colleagueクラスからの通知を受け取るメソッドを定義する。

### ConcreteMediatorクラス
- Mediatorクラスのサブクラス。

### Colleagueクラス
- 「colleague」は「同僚」「仲間」という意味。
- Mediatorクラスに通知を行うクラス。
- Mediatorクラスからの通知を受け取るメソッドを定義する場合もある。

### ConcreteColleagueクラス
- Colleagueクラスのサブクラス。
- 内部にMediatorオブジェクトを保持し、このMediatorオブジェクトを通じて他のConcreteColleagueクラスとやり取りを行う。

# 実演
## 処理の流れ
- ``Userクラス``同士のやり取りを``Chatroomクラス``が仲介する。
- Userクラス同士でメッセージの送受信ができる。その時、Chatroomクラスはメッセージのルーティングを行う。
- UserクラスはChatroom型オブジェクトを保持している。このオブジェクトを通じて他のUser型オブジェクトとやり取りを行う。

## ファイル構造
```sh
MyMediator
  ├── Chatroom.php
  ├── User.php
  └── my_client.php
```

## ソースコード
### Mediatorクラス
兼ConcreteMediatorクラス。
#### Chatroom.php
```Chatroom.php
<?php
namespace DoYouPhp\PhpDesignPattern\Mediator\MyMediator;

use DoYouPhp\PhpDesignPattern\Mediator\MyMediator\User;

/**
 * MediatorクラスとConcreteMediatorクラスに相当する
 */
class Chatroom
{
    // User型インスタンスを配列として保持する
    private $users = array();

    // ログイン時の処理
    public function login(User $user)
    {
        // UserクラスにChatroom型オブジェクトをセットする
        $user->setChatroom($this);
        // ログイン時、$usersに存在しないユーザーであれば$usersに追加する
        // キーはユーザー名とする
        if (!array_key_exists($user->getName(), $this->users)) {
            $this->users[$user->getName()] = $user;
            // 入室のメッセージを出力する
            echo $user->getName().'さんが入室しました'.'<br>'."\n";
        }
    }

    // 相手にメッセージを送る
    public function sendMessage($from, $to, $message)
    {
        // 相手が入室している場合はメッセージを受け取る
        // メッセージはUserクラスのメソッドから出力する
        if (array_key_exists($to, $this->users)) {
            $this->users[$to]->receiveMessage($from, $message);
        } else {
            // 相手が入室していない場合は、メッセージを出力する
            echo $to.'さんは入室していないようです'.'<br>'."\n";
        }
    }
}
```

### Colleagueクラス
兼ConcreteColleagueクラス。
#### User.php
```User.php
<?php
namespace DoYouPhp\PhpDesignPattern\Mediator\MyMediator;

use DoYouPhp\PhpDesignPattern\Mediator\MyMediator\Chatroom;

/**
 * ColleagueクラスとConcreteColleagueクラスに相当する
 */
class User
{
    // Chatroom型インスタンスを保持する
    private $chatroom;
    // ユーザー名
    private $name;

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

    public function getName()
    {
        return $this->name;
    }

    // ログイン時に実行される
    // チャットルームをセットする
    public function setChatroom(Chatroom $value)
    {
        $this->chatroom = $value;
    }

    public function getChatroom()
    {
        return $this->chatroom;
    }

    // メッセージを送る
    // メッセージのルーティングはChatroomクラスで行う
    public function sendMessage($to, $message)
    {
        $this->chatroom->sendMessage($this->name, $to, $message);
    }

    // ルーティングの結果、受け取ったメッセージを表示する
    // Chatroomクラスから差出人の名前とメッセージを受け取る
    public function receiveMessage($from, $message)
    {
        echo $from.'さんから'.$this->getName().'さんへ:'.$message.'<br>'."\n";
    }
}
```

### Clientクラス
#### my_client.php
```my_client.php
<?php
namespace DoYouPhp\PhpDesignPattern\Mediator\MyMediator;

require dirname(dirname(__DIR__)).'/vendor/autoload.php';

use DoYouPhp\PhpDesignPattern\Mediator\MyMediator\Chatroom;
use DoYouPhp\PhpDesignPattern\Mediator\MyMediator\User;

    // Chatroom型インスタンスを生成する
    $chatroom = new Chatroom();

    // User型インスタンスを生成する
    $sasaki = new User('佐々木');
    $suzuki = new User('鈴木');
    $yoshida = new User('吉田');

    // Chatroomクラスからログインのメソッドを実行する
    $chatroom->login($sasaki);
    $chatroom->login($suzuki);
    $chatroom->login($yoshida);

    // メッセージを送信する
    $sasaki->sendMessage('鈴木', 'こんにちは！');
    $suzuki->sendMessage('吉田', 'お久しぶりです！');
    $yoshida->sendMessage('萩原', 'お世話になっています！');
```