php教程:php设计模式介绍之策略模式(3)
把以下这段代码加入到测试环境中以后,你可以确保每一个测试过程从开始的时候就各自独立地运行:
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);
}
}
128
The Strategy Pattern
通过黑体字部分的代码,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);
}
}
130
The Strategy Pattern