mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-07-31 20:20:15 +02:00
Refactored example of Proxy pattern
This commit is contained in:
10
Structural/Proxy/BankAccount.php
Normal file
10
Structural/Proxy/BankAccount.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Structural\Proxy;
|
||||
|
||||
interface BankAccount
|
||||
{
|
||||
public function deposit(int $amount);
|
||||
|
||||
public function getBalance(): int;
|
||||
}
|
24
Structural/Proxy/BankAccountProxy.php
Normal file
24
Structural/Proxy/BankAccountProxy.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Structural\Proxy;
|
||||
|
||||
class BankAccountProxy extends HeavyBankAccount implements BankAccount
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $balance;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
25
Structural/Proxy/HeavyBankAccount.php
Normal file
25
Structural/Proxy/HeavyBankAccount.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Structural\Proxy;
|
||||
|
||||
class HeavyBankAccount implements BankAccount
|
||||
{
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $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);
|
||||
}
|
||||
}
|
@@ -25,15 +25,21 @@ Code
|
||||
|
||||
You can also find this code on `GitHub`_
|
||||
|
||||
Record.php
|
||||
BankAccount.php
|
||||
|
||||
.. literalinclude:: Record.php
|
||||
.. literalinclude:: BankAccount.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
RecordProxy.php
|
||||
HeavyBankAccount.php
|
||||
|
||||
.. literalinclude:: RecordProxy.php
|
||||
.. literalinclude:: HeavyBankAccount.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
BankAccountProxy.php
|
||||
|
||||
.. literalinclude:: BankAccountProxy.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
|
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Structural\Proxy;
|
||||
|
||||
/**
|
||||
* @property string username
|
||||
*/
|
||||
class Record
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* @param string[] $data
|
||||
*/
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function __set(string $name, string $value)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
public function __get(string $name): string
|
||||
{
|
||||
if (!isset($this->data[$name])) {
|
||||
throw new \OutOfRangeException('Invalid name given');
|
||||
}
|
||||
|
||||
return $this->data[$name];
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Structural\Proxy;
|
||||
|
||||
class RecordProxy extends Record
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isDirty = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isInitialized = false;
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
parent::__construct($data);
|
||||
|
||||
// when the record has data, mark it as initialized
|
||||
// since Record will hold our business logic, we don't want to
|
||||
// implement this behaviour there, but instead in a new proxy class
|
||||
// that extends the Record class
|
||||
if (count($data) > 0) {
|
||||
$this->isInitialized = true;
|
||||
$this->isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function __set(string $name, string $value)
|
||||
{
|
||||
$this->isDirty = true;
|
||||
|
||||
parent::__set($name, $value);
|
||||
}
|
||||
|
||||
public function isDirty(): bool
|
||||
{
|
||||
return $this->isDirty;
|
||||
}
|
||||
}
|
@@ -2,24 +2,23 @@
|
||||
|
||||
namespace DesignPatterns\Structural\Proxy\Tests;
|
||||
|
||||
use DesignPatterns\Structural\Proxy\RecordProxy;
|
||||
use DesignPatterns\Structural\Proxy\BankAccountProxy;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ProxyTest extends TestCase
|
||||
{
|
||||
public function testWillSetDirtyFlagInProxy()
|
||||
public function testProxyWillOnlyExecuteExpensiveGetBalanceOnce()
|
||||
{
|
||||
$recordProxy = new RecordProxy([]);
|
||||
$recordProxy->username = 'baz';
|
||||
$bankAccount = new BankAccountProxy();
|
||||
$bankAccount->deposit(30);
|
||||
|
||||
$this->assertTrue($recordProxy->isDirty());
|
||||
}
|
||||
// this time balance is being calculated
|
||||
$this->assertEquals(0, $bankAccount->getBalance());
|
||||
|
||||
public function testProxyIsInstanceOfRecord()
|
||||
{
|
||||
$recordProxy = new RecordProxy([]);
|
||||
$recordProxy->username = 'baz';
|
||||
// inheritance allows for BankAccountProxy to behave to an outsider exactly like ServerBankAccount
|
||||
$bankAccount->deposit(50);
|
||||
|
||||
$this->assertInstanceOf(RecordProxy::class, $recordProxy);
|
||||
// this time the previously calculated balance is returned again without re-calculating it
|
||||
$this->assertEquals(0, $bankAccount->getBalance());
|
||||
}
|
||||
}
|
||||
|
@@ -1,28 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>PHP</ID>
|
||||
<OriginalElement>\DesignPatterns\Structural\Proxy\Record</OriginalElement>
|
||||
<nodes>
|
||||
<node x="4.0" y="0.0">\DesignPatterns\Structural\Proxy\Record</node>
|
||||
<node x="0.0" y="159.0">\DesignPatterns\Structural\Proxy\RecordProxy</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="\DesignPatterns\Structural\Proxy\RecordProxy" target="\DesignPatterns\Structural\Proxy\Record">
|
||||
<point x="0.0" y="-54.5" />
|
||||
<point x="0.0" y="54.5" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic Group" zoom="1.0" x="81.0" y="134.0" />
|
||||
<SelectedNodes>
|
||||
<node>\DesignPatterns\Structural\Proxy\Record</node>
|
||||
</SelectedNodes>
|
||||
<Categories>
|
||||
<Category>Fields</Category>
|
||||
<Category>Constants</Category>
|
||||
<Category>Constructors</Category>
|
||||
<Category>Methods</Category>
|
||||
</Categories>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>PHP</ID>
|
||||
<OriginalElement>\DesignPatterns\Structural\Proxy\BankAccount</OriginalElement>
|
||||
<nodes>
|
||||
<node x="7.5" y="282.0">\DesignPatterns\Structural\Proxy\BankAccountProxy</node>
|
||||
<node x="-58.0" y="123.0">\DesignPatterns\Structural\Proxy\HeavyBankAccount</node>
|
||||
<node x="45.0" y="0.0">\DesignPatterns\Structural\Proxy\BankAccount</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="\DesignPatterns\Structural\Proxy\HeavyBankAccount" target="\DesignPatterns\Structural\Proxy\BankAccount">
|
||||
<point x="0.0" y="-48.0" />
|
||||
<point x="21.5" y="98.0" />
|
||||
<point x="84.75" y="98.0" />
|
||||
<point x="-39.75" y="36.5" />
|
||||
</edge>
|
||||
<edge source="\DesignPatterns\Structural\Proxy\BankAccountProxy" target="\DesignPatterns\Structural\Proxy\BankAccount">
|
||||
<point x="37.5" y="-37.0" />
|
||||
<point x="120.0" y="243.0" />
|
||||
<point x="164.5" y="243.0" />
|
||||
<point x="164.5" y="161.0" />
|
||||
<point x="165.25" y="105.0" />
|
||||
<point x="39.75" y="36.5" />
|
||||
</edge>
|
||||
<edge source="\DesignPatterns\Structural\Proxy\BankAccountProxy" target="\DesignPatterns\Structural\Proxy\HeavyBankAccount">
|
||||
<point x="-37.5" y="-37.0" />
|
||||
<point x="45.0" y="247.0" />
|
||||
<point x="21.5" y="247.0" />
|
||||
<point x="0.0" y="48.0" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic Group" zoom="1.0" x="73.0" y="178.0" />
|
||||
<SelectedNodes />
|
||||
<Categories>
|
||||
<Category>Fields</Category>
|
||||
<Category>Constants</Category>
|
||||
<Category>Constructors</Category>
|
||||
<Category>Methods</Category>
|
||||
</Categories>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 35 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 52 KiB |
Reference in New Issue
Block a user