2.10. Pełnomocnik (Proxy)¶
2.10.1. Przeznaczenie¶
Stosowany jest w celu kontrolowanego tworzenia na żądanie kosztownych obiektów oraz kontroli dostępu do nich.
2.10.2. Przykłady¶
- Doctrine2 używa Pełnomocników do zaimplementowania późnej inicjalizacji (ang. lazy initialization), co przekłada się na sposób pracy z encjami. Zamiast otrzymywać obiekt encji, która na przykład nie może być w pełni zainicjalizowana, otrzymujemy obiekt Pośrednika.
2.10.3. Diagram UML¶

2.10.4. Kod¶
Ten kod znajdziesz również na GitHub.
BankAccount.php
1 2 3 4 5 6 7 8 9 10 11 12 | <?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Proxy;
interface BankAccount
{
public function deposit(int $amount);
public function getBalance(): int;
}
|
HeavyBankAccount.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
declare(strict_types=1);
namespace DesignPatterns\Structural\Proxy;
class HeavyBankAccount implements BankAccount
{
/**
* @var int[]
*/
private array $transactions = [];
public function deposit(int $amount)
{
$this->transactions[] = $amount;
}
public function getBalance(): int
{
// this is the heavy part, imagine all the transactions even from
// years and decades ago must be fetched from a database or web service
// and the balance must be calculated from it
return array_sum($this->transactions);
}
}
|
BankAccountProxy.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Proxy;
class BankAccountProxy extends HeavyBankAccount implements BankAccount
{
private ?int $balance = null;
public function getBalance(): int
{
// because calculating balance is so expensive,
// the usage of BankAccount::getBalance() is delayed until it really is needed
// and will not be calculated again for this instance
if ($this->balance === null) {
$this->balance = parent::getBalance();
}
return $this->balance;
}
}
|
2.10.5. Testy¶
ProxyTest.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 | <?php
declare(strict_types=1);
namespace DesignPatterns\Structural\Proxy\Tests;
use DesignPatterns\Structural\Proxy\BankAccountProxy;
use PHPUnit\Framework\TestCase;
class ProxyTest extends TestCase
{
public function testProxyWillOnlyExecuteExpensiveGetBalanceOnce()
{
$bankAccount = new BankAccountProxy();
$bankAccount->deposit(30);
// this time balance is being calculated
$this->assertSame(30, $bankAccount->getBalance());
// inheritance allows for BankAccountProxy to behave to an outsider exactly like ServerBankAccount
$bankAccount->deposit(50);
// this time the previously calculated balance is returned again without re-calculating it
$this->assertSame(30, $bankAccount->getBalance());
}
}
|