偷懒的代理模式(Proxy Pattern)_PHP_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > PHP > 偷懒的代理模式(Proxy Pattern)

偷懒的代理模式(Proxy Pattern)

 2014/4/4 23:45:04  home198979  程序员俱乐部  我要评论(0)
  • 摘要:代理,百度百科解释道:以他人的名义,在授权范围内进行对被代理人直接发生法律效力的法律行为。玩游戏的同学对代练肯定不陌生,找代练帮忙升级打怪,下面就以此例编写个简单的代理模式:结构如图,首先定义一个游戏接口,接口有游戏的一些基本动作,如登录,打怪,升级。再定义一个玩家的类,继承游戏接口,实现动作。最后定义一个代理类,客户端通过调用代理实际完成玩家的动作。<?phpinterfaceIGamePlayer{publicfunctionlogin($username,$password)
  • 标签:模式 代理 代理模式

代理,百度百科解释道:以他人的名义,在授权范围内进行对被代理人直接发生法律效力的法律行为。

玩游戏的同学对代练肯定不陌生,找代练帮忙升级打怪,下面就以此例编写个简单的代理模式



结构如图,首先定义一个游戏接口,接口有游戏的一些基本动作,如登录,打怪,升级。再定义一个玩家的类,继承游戏接口,实现动作。最后定义一个代理类,客户端通过调用代理实际完成玩家的动作。

?

class="php" name="code"><?php
interface IGamePlayer{
	public function login( $username, $password );
	public function killBoss();
	public function upgrade();
}

class GamePlayer implements IGamePlayer{
	private $username = '';
	public function __construct( $username ) {
		$this->username = $username;
	}
	public function login( $username, $password ) {
		echo $username."登录成功\n";
	}
	public function killBoss() {
		echo $this->username."在打怪!\n";
	}
	public function upgrade() {
		echo $this->username."升级了!\n";
	}
}

class GamePlayerProxy implements IGamePlayer{
	private $gamePlayer = null;
	public function __construct( $gamePlayer ) {
		$this->gamePlayer = $gamePlayer;
	}
	public function login( $username, $password ) {
		$this->gamePlayer->login( $username, $password );
	}
	public function killBoss() {
		$this->gamePlayer->killBoss();
	}
	public function upgrade() {
		$this->gamePlayer->upgrade();
	}
}

$player = new GamePlayer( 'luoxin' );
$proxy = new GamePlayerProxy( $player );
$proxy->login( 'luoxin', 'password' );
$proxy->killBoss();
$proxy->upgrade();
?>
运行结果:
luoxin登录成功
luoxin在打怪!
luoxin升级了!
[Finished in 0.2s]

?

?

代理模式的定义:

为其他对象提供一种代理以控制对这个对象的访问。代理模式也叫委托模式,它是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。代理模式中三个角色的定义:

1、抽象主题角色(例中的IGamePlayer)

抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。

2、具体主题角色(例中的GamePlayer)

也叫做被委托角色,被代理角色。它才是冤大头,也是业务逻辑的具体执行者。

3、代理主题角色(例中的GamePlayerProxy)

也叫委托类,代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

?

代理模式的优点:

1、职责清晰

真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事情,附带结果就是编程简洁清晰。

2、高扩展性

具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

3、智能

见下文的动态代理

?

?

代理模式的扩展:

?

1、普通代理

客户端只能访问代理角色,而不能访问真实角色。

<?php
interface IGamePlayer{
	public function login( $username, $password );
	public function killBoss();
	public function upgrade();
}

class GamePlayer implements IGamePlayer{
	private $username = '';
	public function __construct( $proxy, $username ) {
		if ( !is_object( $proxy ) || get_class( $proxy ) != 'GamePlayerProxy' ) {
			try{
				throw new Exception( "不能创建真实角色" );
			}catch ( Exception $e ) {
				echo 'Caught exception: ',  $e->getMessage(), "\n";
			}
		}else
			$this->username = $username;
	}
	public function login( $username, $password ) {
		echo $username."登录成功\n";
	}
	public function killBoss() {
		echo $this->username."在打怪!\n";
	}
	public function upgrade() {
		echo $this->username."升级了!\n";
	}
}

class GamePlayerProxy implements IGamePlayer{
	private $gamePlayer = null;
	public function __construct( $username ) {
		$this->gamePlayer = new GamePlayer( $this, $username );
	}
	public function login( $username, $password ) {
		$this->gamePlayer->login( $username, $password );
	}
	public function killBoss() {
		$this->gamePlayer->killBoss();
	}
	public function upgrade() {
		$this->gamePlayer->upgrade();
	}
}

$proxy = new GamePlayerProxy( 'luoxin' );
$proxy->login( 'luoxin', 'password' );
$proxy->killBoss();
$proxy->upgrade();

?>
运行结果:
luoxin登录成功
luoxin在打怪!
luoxin升级了!
[Finished in 0.1s]

?运行结果完全相同。在该模式下,调用者只知代理而不知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有任何影响,只要你实现了接口所对应的方法,该模式扩展性要求较高的场合。

?

?

2、强制代理

必须通过真实角色查找到代理角色,否则你不能访问。

<?php
interface IGamePlayer{
	public function login( $username, $password );
	public function killBoss();
	public function upgrade();
	public function getProxy();//新增一个获取代理的方法
}

class GamePlayer implements IGamePlayer{
	private $username = '';
	private $proxy = null;
	public function __construct( $username ) {
		$this->username = $username;
	}
        //实现获取本身代理类
	public function getProxy() {
		$this->proxy = new GamePlayerProxy( $this );
		return $this->proxy;
	}
	public function login( $username, $password ) {
		if ( $this->isProxy() )
			echo $username."登录成功\n";
		else
			echo "请使用指定的代理访问\n";
	}
	public function killBoss() {
		if ( $this->isProxy() )
			echo $this->username."在打怪!\n";
		else
			echo "请使用指定的代理访问\n";
	}
	public function upgrade() {
		if ( $this->isProxy() )
			echo $this->username."升级了!\n";
		else
			echo "请使用指定的代理访问\n";
	}
        //新增判断是否有代理的私有方法
	private function isProxy() {
		return !( $this->proxy == null );
	}
}

class GamePlayerProxy implements IGamePlayer{
	private $gamePlayer = null;
	public function __construct( $gamePlayer ) {
		$this->gamePlayer = $gamePlayer;
	}
	public function login( $username, $password ) {
		$this->gamePlayer->login( $username, $password );
	}
	public function killBoss() {
		$this->gamePlayer->killBoss();
	}
	public function upgrade() {
		$this->gamePlayer->upgrade();
	}
	public function getProxy(){
		return $this;
	}
}

$player = new GamePlayer( 'luoxin' );
$player->killBoss();
$proxy = $player->getProxy();
$proxy->login( 'luoxin', 'password' );
$proxy->killBoss();
$proxy->upgrade();

?>
运行结果:
请使用指定的代理访问
luoxin登录成功
luoxin在打怪!
luoxin升级了!
[Finished in 0.1s]

?记住:强制代理就是要从真实角色查找到代理角色,不允许直接访问真实角色。高层模块只要调用getProxy()就可以访问真实角色的所有方法,它根本就不需要产生一个代理出来,代理的管理已经由真实角色自己完成。

?

?

3、代理是有个性的

一个类可以实现多个接口,完成不同任务的整合。也就是说代理类不仅仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。例如我们找人代练是要交钱的,假设升一级需要250$(好贵啊),这个计算功能就是代理类的个性,它应该在代理的接口中定义。

如图,新增一个IProxy接口,接口中有个计费的方法count,代理类GamePlayerProxy继承IGamePlayer接口的同时也继承IProxy

?

<?php
interface IGamePlayer{
	public function login( $username, $password );
	public function killBoss();
	public function upgrade();
}

interface IProxy{
	public function count();
}

class GamePlayer implements IGamePlayer{
	private $username = '';
	public function __construct( $username ) {
		$this->username = $username;
	}
	public function login( $username, $password ) {
		echo $username."登录成功\n";
	}
	public function killBoss() {
		echo $this->username."在打怪!\n";
	}
	public function upgrade() {
		echo $this->username."升级了!\n";
	}
}

class GamePlayerProxy implements IGamePlayer,IProxy{
	private $gamePlayer = null;
	public function __construct( $gamePlayer ) {
		$this->gamePlayer = $gamePlayer;
	}
	public function login( $username, $password ) {
		$this->gamePlayer->login( $username, $password );
	}
	public function killBoss() {
		$this->gamePlayer->killBoss();
	}
	public function upgrade() {
		$this->gamePlayer->upgrade();
		$this->count();
	}
	public function count() {
		echo "升级总费用是:250$\n";
	}
}

$player = new GamePlayer( 'luoxin' );
$proxy = new GamePlayerProxy( $player );
$proxy->login( 'luoxin', 'password' );
$proxy->killBoss();
$proxy->upgrade();
?>
运行结果:
luoxin登录成功
luoxin在打怪!
luoxin升级了!
升级总费用是:250$
[Finished in 0.2s]

?

?

4、虚拟代理

听起来复杂,其实就是在代理类中每个方法中判断主题对象是否被创建,如果没有,则创建。可以避免被代理对象较多而引起的初始化缓慢的问题。

?

5、动态代理

动态代理在JAVA中有充分的应用,其叼炸天的AOP编程用的就是此模式。在PHP中,用魔术方法__call可以轻松地实现。

?

<?php
interface IGamePlayer{
	public function login( $username, $password );
	public function killBoss();
	public function upgrade();
}

class GamePlayer implements IGamePlayer{
	private $username = '';
	public function __construct( $username ) {
		$this->username = $username;
	}
	public function login( $username, $password ) {
		echo $username."登录成功\n";
	}
	public function killBoss() {
		echo $this->username."在打怪!\n";
	}
	public function upgrade() {
		echo $this->username."升级了!\n";
	}
}

class GamePlayerProxy{//此处不能再继承IGamePlayer接口
	private $gamePlayer = null;
	public function __construct( $gamePlayer ) {
		$this->gamePlayer = $gamePlayer;
	}
	public function __call($method,$args){
                //方法前后可以做很多智能化的处理
		return call_user_func_array(array($this->gamePlayer, $method), $args);
	}
}

$player = new GamePlayer( 'luoxin' );
$proxy = new GamePlayerProxy( $player );
$proxy->login( 'luoxin', 'password' );
$proxy->killBoss();
$proxy->upgrade();
?>
运行结果:
luoxin登录成功
luoxin在打怪!
luoxin升级了!
[Finished in 0.1s]

?

?

?

  • 大小: 7.7 KB
  • 大小: 10 KB
  • 查看图片附件
上一篇: C#每天进步一点--事件 下一篇: 没有下一篇了!
发表评论
用户名: 匿名