3.4. Mediator¶
3.4.1. Purpose¶
This pattern provides an easy to decouple many components working together. It is a good alternative over Observer IF you have a “central intelligence”, like a controller (but not in the sense of the MVC).
All components (called Colleague) are only coupled to the MediatorInterface and it is a good thing because in OOP, one good friend is better than many. This is the key-feature of this pattern.
3.4.2. UML Diagram¶
3.4.3. Code¶
You can also find these code on GitHub
MediatorInterface.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
namespace DesignPatterns\Behavioral\Mediator;
/**
* MediatorInterface is a contract for the Mediator
* This interface is not mandatory but it is better for LSP concerns
*/
interface MediatorInterface
{
/**
* sends the response
*
* @param string $content
*/
public function sendResponse($content);
/**
* makes a request
*/
public function makeRequest();
/**
* queries the DB
*/
public function queryDb();
}
|
Mediator.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?php
namespace DesignPatterns\Behavioral\Mediator;
use DesignPatterns\Behavioral\Mediator\Subsystem;
/**
* Mediator is the concrete Mediator for this design pattern.
* In this example, I have made a "Hello World" with the Mediator Pattern.
*/
class Mediator implements MediatorInterface
{
/**
* @var Subsystem\Server
*/
protected $server;
/**
* @var Subsystem\Database
*/
protected $database;
/**
* @var Subsystem\Client
*/
protected $client;
/**
* @param Subsystem\Database $db
* @param Subsystem\Client $cl
* @param Subsystem\Server $srv
*/
public function setColleague(Subsystem\Database $db, Subsystem\Client $cl, Subsystem\Server $srv)
{
$this->database = $db;
$this->server = $srv;
$this->client = $cl;
}
/**
* make request
*/
public function makeRequest()
{
$this->server->process();
}
/**
* query db
* @return mixed
*/
public function queryDb()
{
return $this->database->getData();
}
/**
* send response
*
* @param string $content
*/
public function sendResponse($content)
{
$this->client->output($content);
}
}
|
Colleague.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <?php
namespace DesignPatterns\Behavioral\Mediator;
/**
* Colleague is an abstract colleague who works together but he only knows
* the Mediator, not other colleague.
*/
abstract class Colleague
{
/**
* this ensures no change in subclasses
*
* @var MediatorInterface
*/
private $mediator;
/**
* @param MediatorInterface $medium
*/
public function __construct(MediatorInterface $medium)
{
// in this way, we are sure the concrete colleague knows the mediator
$this->mediator = $medium;
}
// for subclasses
protected function getMediator()
{
return $this->mediator;
}
}
|
Subsystem/Client.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php
namespace DesignPatterns\Behavioral\Mediator\Subsystem;
use DesignPatterns\Behavioral\Mediator\Colleague;
/**
* Client is a client that make request et get response
*/
class Client extends Colleague
{
/**
* request
*/
public function request()
{
$this->getMediator()->makeRequest();
}
/**
* output content
*
* @param string $content
*/
public function output($content)
{
echo $content;
}
}
|
Subsystem/Database.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php
namespace DesignPatterns\Behavioral\Mediator\Subsystem;
use DesignPatterns\Behavioral\Mediator\Colleague;
/**
* Database is a database service
*/
class Database extends Colleague
{
/**
* @return string
*/
public function getData()
{
return "World";
}
}
|
Subsystem/Server.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php
namespace DesignPatterns\Behavioral\Mediator\Subsystem;
use DesignPatterns\Behavioral\Mediator\Colleague;
/**
* Server serves responses
*/
class Server extends Colleague
{
/**
* process on server
*/
public function process()
{
$data = $this->getMediator()->queryDb();
$this->getMediator()->sendResponse("Hello $data");
}
}
|
3.4.4. Test¶
Tests/MediatorTest.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <?php
namespace DesignPatterns\Tests\Mediator\Tests;
use DesignPatterns\Behavioral\Mediator\Mediator;
use DesignPatterns\Behavioral\Mediator\Subsystem\Database;
use DesignPatterns\Behavioral\Mediator\Subsystem\Client;
use DesignPatterns\Behavioral\Mediator\Subsystem\Server;
/**
* MediatorTest tests hello world
*/
class MediatorTest extends \PHPUnit_Framework_TestCase
{
protected $client;
protected function setUp()
{
$media = new Mediator();
$this->client = new Client($media);
$media->setColleague(new Database($media), $this->client, new Server($media));
}
public function testOutputHelloWorld()
{
// testing if Hello World is output :
$this->expectOutputString('Hello World');
// as you see, the 3 components Client, Server and Database are totally decoupled
$this->client->request();
// Anyway, it remains complexity in the Mediator that's why the pattern
// Observer is preferable in mnay situations.
}
}
|