2.10. Proxy
2.10.1. Amaç
Maliyetli olan veya yinelenmesi (duplicate) mümkün olmayan bir şeyi arayüzlemek.
2.10.2. Örnekler
Doctrine2, kullanıcı kendi varlık sınıflarını (entity class) kullanırken ve asla aracıları kullanmaz ya da aracılara dokunmazken, framework içindeki özel yöntemleri (magic method) (örn: yavaş başlatım (lazy initialization)) uygulamak için aracıları kullanır.
2.10.3. UML Diyagramı

2.10.4. Kod
Bu kodu Github üzerinde de bulabilirsiniz.
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. Test
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}