《PHP設(shè)計(jì)模式介紹》第七章 策略模式(2)_PHP教程
推薦:《PHP設(shè)計(jì)模式介紹》第六章 偽對(duì)象模式面向?qū)ο蟮木幊讨载S富多彩,部分是由于對(duì)象間的相互聯(lián)系與作用。一個(gè)單一的對(duì)象就能封裝一個(gè)復(fù)雜的子系統(tǒng),使那些很復(fù)雜的操作能夠通過一些方法的調(diào)用而簡(jiǎn)化。(無所不在的數(shù)據(jù)庫(kù)連接就是這
把一下這段代碼加入到測(cè)試環(huán)境中以后,你可以確保每一個(gè)測(cè)試過程從開始的時(shí)候就各自獨(dú)立地運(yùn)行:
| The Strategy Pattern 127 class VarCacheTestCase extends UnitTestCase { function setup() { @unlink(‘cache/foo.php’); } // ... } |
現(xiàn)在緩存的文件在每一次測(cè)試執(zhí)行之前都沒刪除掉了,這保證了每一次測(cè)試運(yùn)行都是相互獨(dú)立的。(測(cè)試驅(qū)動(dòng)的開發(fā)更實(shí)用的方法是你可以寫一個(gè)VarCache::clear()方式函數(shù)去處理一個(gè)緩存的參數(shù)的清除工作。)
當(dāng)上一次代碼執(zhí)行出來的緩存結(jié)果被清除了,測(cè)試重新開始運(yùn)行,這意味著你可以繼續(xù)測(cè)試并編寫新的代碼。
| 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()); } |
上面的測(cè)試驗(yàn)證VarCache::get()返回的值是否與用VarCache::set()設(shè)置的相同。
|
class VarCache { |
通過黑體字部分的代碼,VarCache::set() 方式函數(shù)把參數(shù)$value的內(nèi)容寫到文件中,并用VarCache::get() 方式函數(shù)通過file_get_content() 從文件中把內(nèi)容讀取出來.
從目前的執(zhí)行情況來看,對(duì)于字符串和數(shù)字的操作是沒有問題的,但是對(duì)于更復(fù)雜的參數(shù)比如數(shù)組和對(duì)象,執(zhí)行起來就會(huì)出現(xiàn)問題了。我們用下面的代碼進(jìn)行處理:
| 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())); } |
由于篇幅的關(guān)系,我們直接調(diào)到這個(gè)執(zhí)行過程的結(jié)束部分,它隨后也將實(shí)現(xiàn)策略式的判斷。
這里就是增加一系列操作用來完善VarCache的地方。
| class VarCache { //... function get() { if ($this->isValid()) { include $this->_name.’.php’; return $cached_content; } //... } |
在這里關(guān)鍵性的改變是get() 方式函數(shù)(并且讓PHP去驗(yàn)證有效性。
同時(shí),get()返回參數(shù)$cached_content的值,所以無論set() 如果操作,它必須設(shè)置這個(gè)變量!
因此,對(duì)于數(shù)字來說,執(zhí)行出來是什么樣的結(jié)果呢?
| 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); } } |
看起來對(duì)于一個(gè)數(shù)字,執(zhí)行起來是沒有問題的,那么對(duì)于字符串如何呢?對(duì)于字符串,緩存文件的數(shù)據(jù)編寫方式就必須用= ‘%s’;結(jié)尾而不是= %s;。所以在這里我們需要引入一個(gè)“type” 參數(shù):它用來指定緩存的數(shù)據(jù)類型是一個(gè)整型還是字符串。為了更容易地增加更多的數(shù)據(jù)類型,我們分別在set()和_getTemplate()函數(shù)增加一個(gè)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); } } |
現(xiàn)在,構(gòu)造函數(shù)增加了第二個(gè)可選的參數(shù)用來確定第一個(gè)參數(shù)的數(shù)據(jù)類型是數(shù)字類型還是字符串。這個(gè)類的最終形式變?yōu)檎?qǐng)看下面代碼,包括了一個(gè)‘serialize’ 用來存儲(chǔ)數(shù)據(jù)、對(duì)象等復(fù)雜數(shù)據(jù)的存儲(chǔ)類型。
| 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); } } |
請(qǐng)注意_getTemplate()和set() 函數(shù)中的case判斷語句。它們都是基于同一個(gè)$_type 實(shí)例參數(shù)的。get() 函數(shù)中卻沒有受到$_type的影響,所以看起來因?yàn)榇鎯?chǔ)的數(shù)據(jù)類型的變化只影響到數(shù)據(jù)的存儲(chǔ)過程。同時(shí),多重的case條件判斷也是一個(gè)提示,這個(gè)地方如果使用了策略的設(shè)計(jì)模式會(huì)更好。
分享:《PHP設(shè)計(jì)模式介紹》第五章 注冊(cè)模式我們通常認(rèn)為避免使用全局變量是一種好的選擇,因此,對(duì)象經(jīng)常被作為參數(shù)從一段代碼傳遞到另一段。但是傳遞實(shí)例的一個(gè)問題就是對(duì)象有時(shí)候不知道將要傳遞給誰——?經(jīng)過一個(gè)函數(shù)后才被傳
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁(yè)面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語言構(gòu)造器介紹
- php/js獲取客戶端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國(guó)語言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
- 相關(guān)鏈接:
- 教程說明:
PHP教程-《PHP設(shè)計(jì)模式介紹》第七章 策略模式(2)
。