2.10. Пълномощно

2.10.1. Предназначение

Да се свързва с всичко, което е скъпо или невъзможно да се дублира.

2.10.2. Примери

  • Doctrine2 използва прокси, за да внедри в тях магия на фреймуърка (напр. Мързелива инициализация), докато потребителят все още работи със собствените си класове на субекти и никога няма да използва или докосва прокситата

2.10.3. UML Диаграма

Alt Proxy UML Diagram

2.10.4. Код

Можете също да намерите този код в GitHub

BankAccount.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Proxy;
 6
 7interface BankAccount
 8{
 9    public function deposit(int $amount);
10
11    public function getBalance(): int;
12}

HeavyBankAccount.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Proxy;
 6
 7class HeavyBankAccount implements BankAccount
 8{
 9    /**
10     * @var int[]
11     */
12    private array $transactions = [];
13
14    public function deposit(int $amount)
15    {
16        $this->transactions[] = $amount;
17    }
18
19    public function getBalance(): int
20    {
21        // this is the heavy part, imagine all the transactions even from
22        // years and decades ago must be fetched from a database or web service
23        // and the balance must be calculated from it
24
25        return array_sum($this->transactions);
26    }
27}

BankAccountProxy.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Proxy;
 6
 7class BankAccountProxy extends HeavyBankAccount implements BankAccount
 8{
 9    private ?int $balance = null;
10
11    public function getBalance(): int
12    {
13        // because calculating balance is so expensive,
14        // the usage of BankAccount::getBalance() is delayed until it really is needed
15        // and will not be calculated again for this instance
16
17        if ($this->balance === null) {
18            $this->balance = parent::getBalance();
19        }
20
21        return $this->balance;
22    }
23}

2.10.5. Тест

ProxyTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Proxy\Tests;
 6
 7use DesignPatterns\Structural\Proxy\BankAccountProxy;
 8use PHPUnit\Framework\TestCase;
 9
10class ProxyTest extends TestCase
11{
12    public function testProxyWillOnlyExecuteExpensiveGetBalanceOnce()
13    {
14        $bankAccount = new BankAccountProxy();
15        $bankAccount->deposit(30);
16
17        // this time balance is being calculated
18        $this->assertSame(30, $bankAccount->getBalance());
19
20        // inheritance allows for BankAccountProxy to behave to an outsider exactly like ServerBankAccount
21        $bankAccount->deposit(50);
22
23        // this time the previously calculated balance is returned again without re-calculating it
24        $this->assertSame(30, $bankAccount->getBalance());
25    }
26}