1.5. Mediator

1.5.1. Intent

According to the Gang of Four, the Mediator is a way to “define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently” (Design Patterns: Elements of Reusable Object-Oriented Software, 2013, p. 273).

1.5.2. When to use it?

Mediator pattern should be used when a large set of objects has too many direct relationships and you want to reduce that complexity. It’s a way to balance distribution of behavior among objects with loose coupling.

1.5.3. Diagram

Created using PhpStorm and yFiles.

Class diagram of the Mediator pattern

1.5.4. Implementation

AbstractColleague.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
<?php

namespace Phpatterns\Behavioral\Mediator;

abstract class AbstractColleague
{
    /** @var TaxiCallCenterInterface */
    private $mediator;

    /**
     * @param TaxiCallCenterInterface $mediator
     */
    public function __construct(TaxiCallCenterInterface $mediator)
    {
        $this->mediator = $mediator;
    }

    /**
     * @return TaxiCallCenterInterface
     */
    protected function getMediator()
    {
        return $this->mediator;
    }
}

Customer.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 Phpatterns\Behavioral\Mediator\Colleague;

use Phpatterns\Behavioral\Mediator;

class Customer extends Mediator\AbstractColleague
{
    /**
     * @param Mediator\TaxiCallCenterInterface $mediator
     */
    public function __construct(Mediator\TaxiCallCenterInterface $mediator)
    {
        parent::__construct($mediator);
    }

    /**
     * @return bool
     */
    public function requestRace()
    {
        return $this->getMediator()->requestRace();
    }

    /**
     * @return bool
     */
    public function confirm()
    {
        return true;
    }
}

Taxi.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
<?php

namespace Phpatterns\Behavioral\Mediator\Colleague;

use Phpatterns\Behavioral\Mediator;

class Taxi extends Mediator\AbstractColleague
{
    /** @var bool */
    private $available;

    /**
     * @param Mediator\TaxiCallCenterInterface $mediator
     */
    public function __construct(Mediator\TaxiCallCenterInterface $mediator)
    {
        parent::__construct($mediator);
        $this->available = true;
    }

    /**
     * @param bool $available
     */
    public function setAvailable($available)
    {
        $this->available = $available;
    }

    /**
     * @return bool
     */
    public function request()
    {
        if ($this->available) {
            $this->setAvailable(false);
            return $this->getMediator()->acceptRace();
        }

        return false;
    }
}

TaxiCallCenterInterface.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace Phpatterns\Behavioral\Mediator;

/**
 * Interface TaxiCallCenterInterface
 * Classes implementing that interface will be used as Mediators
 */
interface TaxiCallCenterInterface
{
    /**
     * @return bool
     */
    public function requestRace();

    /**
     * @return bool
     */
    public function acceptRace();
}

YellowTaxiCallCenter.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
<?php

namespace Phpatterns\Behavioral\Mediator\TaxiCallCenter;

use Phpatterns\Behavioral\Mediator;

class YellowTaxiCallCenter implements Mediator\TaxiCallCenterInterface
{
    /** @var Mediator\AbstractColleague */
    private $taxi;

    /** @var Mediator\AbstractColleague */
    private $customer;

    /**
     * @param Mediator\AbstractColleague $taxi
     * @return $this
     */
    public function setTaxi($taxi)
    {
        $this->taxi = $taxi;
        return $this;
    }

    /**
     * @param Mediator\AbstractColleague $customer
     * @return $this
     */
    public function setCustomer($customer)
    {
        $this->customer = $customer;
        return $this;
    }

    /**
     * @return bool
     */
    public function requestRace()
    {
        return $this->taxi->request();
    }

    /**
     * @return bool
     */
    public function acceptRace()
    {
        return $this->customer->confirm();
    }
}

1.5.5. 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
<?php

namespace Test\Phpatterns\Behavioral\Mediator;

use Phpatterns\Behavioral\Mediator;
use Phpatterns\Behavioral\Mediator\TaxiCallCenter;
use Phpatterns\Behavioral\Mediator\Colleague;

class MediatorTest extends \PHPUnit_Framework_TestCase
{
    /** @var Colleague\Customer */
    private $customer;

    protected function setUp()
    {
        $mediator = new TaxiCallCenter\YellowTaxiCallCenter();

        $this->customer = new Colleague\Customer($mediator);
        $taxi = new Colleague\Taxi($mediator);

        $mediator
            ->setCustomer($this->customer)
            ->setTaxi($taxi);
    }

    public function testTaxiRequest()
    {
        $this->assertTrue($this->customer->requestRace());
    }
}