PHP程序员站--PHP编程开发平台
 当前位置:主页 >> PHP高级编程 >> 高级应用 >> 

PHP设计模式介绍 第七章 策略模式

PHP设计模式介绍 第七章 策略模式

来源:互联网  作者:  发布时间:2010-05-21
在编写面向对象的代码的时,有些时候你需要一个能够自己根据不

把一下这段代码加入到测试环境中以后,你可以确保每一个测试过程从开始的时候就各自独立地运行:


The Strategy Pattern  127
class  VarCacheTestCase  extends  UnitTestCase  {
function  setup()  {
@unlink(‘cache/foo.php’);
}
//  ...
}


现在缓存的文件在每一次测试执行之前都没删除掉了,这保证了每一次测试运行都是相互独立的。(测试驱动的开发更实用的方法是你可以写一个VarCache::clear()方式函数去处理一个缓存的参数的清除工作。)

当上一次代码执行出来的缓存结果被清除了,测试重新开始运行,这意味着你可以继续测试并编写新的代码。

class  VarCacheTestCase  extends  UnitTestCase  {
function  setup()  {  /*  ...  */  }
function  TestUnsetValueIsInvalid()  {  /*  ...  */  } function  TestIsValidTrueAfterSet()  {  /*  ...  */  } function  TestCacheRetainsValue()  {
$test_val  =  ‘test’.rand(1,100);
$cache  =&  new  VarCache(‘foo’);
$cache->set($test_val);
$this->assertEqual($test_val,  $cache->get());
}


上面的测试验证VarCache::get()返回的值是否与用VarCache::set()设置的相同。

class  VarCache  {
var  $_name;
function  VarCache($name)  {  /*  ...  */  } function  isValid()  {  /*  ...  */  } function  get()  {
if  ($this->isValid())  {
return  file_get_contents($this->_name.’.php’);
}
}
function  set($value)  {
$file_handle  =  fopen($this->_name.’.php’,  ‘w’); fwrite($file_handle,$value); fclose($file_handle);
}
}


通过黑体字部分的代码,VarCache::set() 方式函数把参数$value的内容写到文件中,并用VarCache::get() 方式函数通过file_get_content() 从文件中把内容读取出来.

从目前的执行情况来看,对于字符串和数字的操作是没有问题的,但是对于更复杂的参数比如数组和对象,执行起来就会出现问题了。我们用下面的代码进行处理:

 

class  VarCacheTestCase  extends  UnitTestCase  {
//  ...
function  TestStringFailsForArray()  {
$test_val  =  array(‘one’,’two’);
$cache  =&  new  VarCache(‘foo’);
$cache->set($test_val);
$this->assertError(‘Array  to  string  conversion’);
$this->assertNotEqual($test_val,  $cache->get());
$this->assertEqual(‘array’,strtolower($cache->get()));
}


由于篇幅的关系,我们直接调到这个执行过程的结束部分,它随后也将实现策略式的判断。

这里就是增加一系列操作用来完善VarCache的地方。

class  VarCache  {
//...
function  get()  {
if  ($this->isValid())  {
include  $this->_name.’.php’;
return  $cached_content;
}
//...
}

 
在这里关键性的改变是get() 方式函数(并且让PHP去验证有效性。
同时,get()返回参数$cached_content的值,所以无论set() 如果操作,它必须设置这个变量!
因此,对于数字来说,执行出来是什么样的结果呢?


class  VarCache  {
//...
function  set($value)  {
$file_handle  =  fopen($this->_name.’.php’,  ‘w’);
$template  =  ‘<?php  $cached_content  =  %s;’;
$content  =  sprintf($template
The Strategy Pattern  129
,(float)$value);
fwrite($file_handle,  $content);
fclose($file_handle);
}
}

看起来对于一个数字,执行起来是没有问题的,那么对于字符串如何呢?对于字符串,缓存文件的数据编写方式就必须用=  ‘%s’;结尾而不是=  %s;。所以在这里我们需要引入一个“type” 参数:它用来指定缓存的数据类型是一个整型还是字符串。为了更容易地增加更多的数据类型,我们分别在set()和_getTemplate()函数增加一个case 判断。

class  VarCache  {
var  $_name;
var  $_type;
function  VarCache($name,  $type=’string’)  {
$this->_name  =  ‘cache/’.$name;
$this->_type  =  $type;
}
//  ...
function  _getTemplate()  {
$template  =  ‘<?php  $cached_content  =  ‘;
switch  ($this->_type)  {
case  ‘string’:
$template  .=  “‘%s’;”;
break;
case  ‘numeric’:
$template  .=  ‘%s;’;


break;
default:
trigger_error(‘invalid  cache  type’);
}
return  $template;
}
function  set($value)  {
$file_handle  =  fopen($this->_name.’.php’,  ‘w’);
switch  ($this->_type)  {
case  ‘string’:
$content  =  sprintf($this->_getTemplate()
,str_replace(“‘“,”\\’”,$value));
break;
case  ‘numeric’:
$content  =  sprintf($this->_getTemplate()
,(float)$value);
break;
default:
trigger_error(‘invalid  cache  type’);
}
fwrite($file_handle,  $content);
fclose($file_handle);
}
}
 
现在,构造函数增加了第二个可选的参数用来确定第一个参数的数据类型是数字类型还是字符串。这个类的最终形式变为请看下面代码,包括了一个‘serialize’ 用来存储数据、对象等复杂数据的存储类型。

class  VarCache  {
var  $_name;
var  $_type;
function  VarCache($name,  $type=’serialize’)  {
$this->_name  =  ‘cache/’.$name;
$this->_type  =  $type;
}
function  isValid()  {
return  file_exists($this->_name.’.php’);
}
function  get()  {
if  ($this->isValid())  {
include  $this->_name.’.php’
return  $cached_content;
}
}
function  _getTemplate()  {
$template  =  ‘<?php  $cached_content  =  ‘;

switch  ($this->_type)  {
case  ‘string’:
$template  .=  “‘%s’;”;
break;
case  ‘serialize’:
$template  .=  “unserialize(stripslashes(‘%s’));”;
break;
case  ‘numeric’:
$template  .=  ‘%s;’;
break;
default:
trigger_error(‘invalid  cache  type’);
}
return  $template;
}
function  set($value)  {
$file_handle  =  fopen($this->_name.’.php’,  ‘w’);
switch  ($this->_type)  {
case  ‘string’:
$content  =  sprintf($this->_getTemplate()
,str_replace(“‘“,”\\’”,$value));
break;
case  ‘serialize’:
$content  =  sprintf($this->_getTemplate()
,addslashes(serialize($value)));
break;
case  ‘numeric’:
$content  =  sprintf($this->_getTemplate()
,(float)$value);
break;
default:
trigger_error(‘invalid  cache  type’);
}
fwrite($file_handle,  $content);
The Strategy Pattern  131
fclose($file_handle);
}
}

请注意_getTemplate()和set() 函数中的case判断语句。它们都是基于同一个$_type 实例参数的。get() 函数中却没有受到$_type的影响,所以看起来因为存储的数据类型的变化只影响到数据的存储过程。同时,多重的case条件判断也是一个提示,这个地方如果使用了策略的设计模式会更好。


延伸阅读:
从魔兽看PHP设计模式
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
PHP设计模式介绍 第三章 工厂模式
PHP设计模式介绍 第四章 单件模式
PHP设计模式介绍 第五章 注册模式
PHP设计模式介绍 第六章 伪对象模式

Tags: php   设计模式   策略模式   设计   模式  
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号