本文同步更新於blog
情境:以下是某搜寻功能
<?php
namespace App\ProxyPattern\Cache;
use App\ProxyPattern\Cache\Database;
class Program
{
/**
* @var Database
*/
protected $database;
public function __construct()
{
$this->database = new Database();
}
/**
* @param string $keyword
* @return array
*/
public function search(string $keyword): array
{
return $this->database->read($keyword);
}
}
<?php
namespace App\ProxyPattern\Cache;
class Database
{
/**
* @param string $keyword
* @return array
*/
public function read(string $keyword): array
{
if ($keyword == 'sushi') {
return ['Bear Sushi', 'Lin Sushi', 'Alysa Sushi'];
}
return [];
}
}
老板希望搜寻时,若是已搜寻过的资料,
便由快取返回,不再呼叫实体资料库。
让我们用代理模式改造它。
需求一:实现快取代理
<?php
namespace App\ProxyPattern\Cache\Contracts;
interface Readable
{
/**
* @param string $keyword
* @return array
*/
public function read(string $keyword): array;
}
<?php
namespace App\ProxyPattern\Cache;
use App\ProxyPattern\Cache\Contracts\Readable;
class Database implements Readable
{
/**
* @param string $keyword
* @return array
*/
public function read(string $keyword): array
{
if ($keyword == 'sushi') {
return ['Bear Sushi', 'Lin Sushi', 'Alysa Sushi'];
}
return [];
}
}
<?php
namespace App\ProxyPattern\Cache;
use App\ProxyPattern\Cache\Contracts\Readable;
class CacheProxy implements Readable
{
/**
* @var array
*/
protected $cached = [];
/**
* @var Database
*/
protected $database;
public function __construct()
{
$this->database = new Database();
}
/**
* @param string $keyword
* @return array
*/
public function read(string $keyword): array
{
if (isset($this->cached[$keyword])) {
return $this->cached[$keyword];
}
$result = $this->database->read($keyword);
$this->cached[$keyword] = $result;
return $result;
}
}
<?php
namespace App\ProxyPattern\Cache;
use App\ProxyPattern\Cache\CacheProxy;
class Program
{
/**
* @var CacheProxy
*/
protected $proxy;
public function __construct()
{
$this->proxy = new CacheProxy();
}
/**
* @param string $keyword
* @return array
*/
public function search(string $keyword): array
{
return $this->proxy->read($keyword);
}
}
这下子客户端搜寻时,若快取代理有资料,便会直接返回结果。
[单一职责原则]
我们将实体类别与代理类别视作两种不同的职责。
代理类别主要处理访问实体类别的行为。
[开放封闭原则]
当我们需要实现不属於实体类别的职责时(例如:关键字被搜寻次数),
我们可以在代理类别中实现,不须修改实体类别的程序码。
若有需要其他控制访问的职责时,也可以新增代理类别。
除了上述的提出介面的委派方法外,
也有人用继承的手法修改行为,但我个人比较不喜欢。
最後附上类别图:
(注:若不熟悉 UML 类别图,可参考UML类别图说明。)
ʕ •ᴥ•ʔ:代理类别就像是实体类别的经纪人一样。
<<: Sass/Css 设计模式(Smacss) DAY37
上一篇我们提到很多人会选择Azure来结合LineBot,其实还有很多提供免费方案的云端服务器!可以...
使用 React 作为前端架构的朋友对於 Flux 应该都不陌生,React 也内建了 Flux 让...
经过 20 天的练习,我们已经大致掌握了 TeamCity 的基本功能,刚好是一个很好的机会来回顾一...
挑战最後一日的题目真的让我想了很久,倒底该放什麽元件来压轴才好?要写一个综合演练,把前面的元件都拿出...
前面花了点时间介绍了 MVC,今天终於要进入正题啦! 我会以一个电玩专卖店的购物网站为主题,并且从後...