//传统方法
$db = IMooc\Factory::getDatabase('slave');
$info = $db->query('select name from user where id=1 limit 1');
$db1 = IMooc\Factory::getDatabase('master');
$info = $db->query("update user name='lili' where id=1 limit 1");
index.php
//不再直接去操作数据库,而是先创建代理对象
$proxy = new IMooc\Proxy();
//这样在代码中就看不到对数据库的存取实际的位置
$proxy->getUserName($id);
$proxy->setUserName($id,$proxy);
Proxy.php
<?php
namespace IMooc;
class Proxy implements IUserProxy
{
//表示读操作
public function getUserName($id)
{
$db = Factory::getDatabase('slave');
$db->query("select name from user where id=$id limit 1");
}
//表示写操作
public function setUserName($id,$name)
{
$db = Factory::getDatabase('master');
$db->query("select user set name=$name where id=$id limit 1");
}
}
IUserProxy.php
<?php
namespace IMooc;
interface IUserProxy
{
public function getUserName($id);
public function setUserName($id,$name);
}
PHP的代理模式
代理模式与父类和接口的异同
相同点:代理模式的作用和父类以及接口和组合的作用类似,都是为了聚合共用部分,减少公共部分的代码
不同点:
相比起父类,他们的语境不同,父类要表达的含义是 is-a, 而代理要表达的含义更接近于接口, 是 has-a,而且使用代理的话应了一句话"少用继承,多用组合",要表达的意思其实也就是降低耦合度了
相比起接口,他们实现的功能又不太一样,语境都是has-a,不过接口是has-a-function,而代理对象时是has-a-object,这个object是has-a-function的object,此外,接口是为了说明这个类拥有什么功能,却没有具体实现,实现了多态,而代理对象不但拥有这个功能,还拥有这个功能的具体实现
对于组合来说,他比组合更具灵活性,比如我们将代理对象设为private,那么我可以选择只提供一部分的代理功能,例如Printer的某一个或两个方法,又或者在提供Printer的功能的时候加入一些其他的操作,这些都是可以的
<?php
class Printer //代理对象,一台打印机
{
public function printSth()
{
echo 'Printer<br/>';
}
}
class TestShop //这是一个文印处理店,只文印,卖纸,不照相
{
private $printer;
public function __construct(Printer $printer)
{
$this->printer = $printer;
}
public function sellPaper()
{
echo 'sell Paper<br/>';
}
public function __call($method,$args) //将代理对象有的功能交给代理对象处理
{
if(method_exists($this->printer, $method))
{
$this->printer->$method($args);
}
}
}
class PhotoShop //这是一个照相店,只文印,拍照,不卖纸
{
//这是一个照相店,只文印,拍照,不卖纸
private $printer;
public function __construct(Printer $printer) {
$this->printer = $printer;
}
public function takePhotos() { //照相
echo 'take photos for you <br/>';
}
public function __call($method, $args) { //将代理对象有的功能交给代理对象处理
if(method_exists($this->printer, $method)) {
$this->printer->$method($args);
}
}
}
$printer = new Printer();
$textShop = new TestShop($printer);
$photoShop = new PhotoShop($printer);
$textShop->printSth();
$photoShop->printSth();
文印处理店和照相店都具有文印的功能,所以我们可以将文印的功能代理给一台打印机,这里打印机只有一个功能,假如打印机还有n个功能,我们使用__call()方法就能够省去很多重复的代码了
假如是使用继承,这样语境上就不合理,一个店显然不应该继承一台打印机
而使用接口,因为我们的功能实现都是一样,也没有必要去重新实现接口的功能
所以此处使用代理是最佳选择
代理模式是把难复制的、占资源多的、远程速度慢的对象,各自对应一个代理对象,被代理后进行本地的操作。对每个被代理的对象,都可以进行本地的个性化扩展。使一些不够完善的对象更加好的适应本地操作。