欧美日韩精品在线,国内精品久久久久久久久,一级毛片恃级毛片直播,清纯唯美亚洲综合欧美色

《PHP設(shè)計(jì)模式介紹》第七章 策略模式_PHP教程

編輯Tag賺U幣
教程Tag:暫無Tag,歡迎添加,賺取U幣!

推薦:《PHP設(shè)計(jì)模式介紹》第六章 偽對象模式
面向?qū)ο蟮木幊讨载S富多彩,部分是由于對象間的相互聯(lián)系與作用。一個(gè)單一的對象就能封裝一個(gè)復(fù)雜的子系統(tǒng),使那些很復(fù)雜的操作能夠通過一些方法的調(diào)用而簡化。(無所不在的數(shù)據(jù)庫連接就是這

在編寫面向?qū)ο蟮拇a的時(shí),有些時(shí)候你需要一個(gè)能夠自己根據(jù)不同的條件來引入不同的操作對象實(shí)例。例如,一個(gè)菜單功能能夠根據(jù)用戶的“皮膚”首選項(xiàng)來決定是否采用水平的還是垂直的排列形式,或者一個(gè)計(jì)費(fèi)系統(tǒng)可以自行根據(jù)用戶的收貨地址來決定稅率。

一般來講,一個(gè)控制菜單的對象實(shí)例包括了add(), delete(), 和 replace()等菜單元素;并通過set()進(jìn)行配置,用render()來管理顯示模式。無論你想生成什么樣子的菜單,你都可以用同一個(gè)對象類來處理。不同菜單的對象實(shí)例只是一些方式函數(shù)的運(yùn)算規(guī)則不同罷了,至少在剛才的例子里面render()函數(shù)是不同的。

但是如果你需要增加菜單的顯示模式種類,或者你需要根據(jù)用戶的國家、省份等信息來判斷菜單排列的順序的時(shí)候,該怎么做呢?而且如果有許多的方式函數(shù)都是經(jīng)常變化的,那么簡單的類封裝將變得復(fù)雜、難易理解和升級的。

問題

怎么輕松地改變對象實(shí)例的執(zhí)行過程,因而在代碼執(zhí)行的時(shí)候動態(tài)地改變執(zhí)行過程?一旦實(shí)現(xiàn)了這個(gè)功能,如果去編寫這樣的類定義從而讓維護(hù)和升級變得非常簡單呢?

解決辦法

當(dāng)一個(gè)類封裝了多個(gè)操作的時(shí)候,對象實(shí)例可以動態(tài)地選擇這些操作來進(jìn)行,可以用策略模式來把對象本身和運(yùn)算規(guī)則區(qū)分開來。或者,更簡單的處理是類里面定義的方式函數(shù)用case語句來進(jìn)行控制。當(dāng)然更簡單的方法是使用策略模式。

策略模式功能非常強(qiáng)大,因?yàn)檫@個(gè)設(shè)計(jì)模式本身的核心思想就是面向?qū)ο缶幊痰亩嘈涡缘乃枷搿?/p>

就在編程領(lǐng)域之外,有許多例子是關(guān)于策略模式的。如果我需要在清晨從家里去上班,我可以有幾個(gè)策略可以考慮:我可以開車,乘坐公交車,走路,汽車或者甚至是搭乘直升飛機(jī)。每個(gè)策略都可以得到相同的結(jié)果,但是它們使用了不同的資源。選擇策略的依據(jù)是費(fèi)用,時(shí)間,使用工具還有每種方式的方便程度 。一個(gè)很好的策略也許在第二天就不能再被使用的,所以策略的選擇是相對的。

你已經(jīng)在前面的工廠模式章節(jié)看到了和策略模式相似的例子:因?yàn)椴煌匦缘馁M(fèi)用計(jì)算方式不同,所以Monopoly游戲的框架使用了許多相似的特性類,但是因?yàn)橘M(fèi)用的計(jì)算不是從類本身獲得,所以這個(gè)費(fèi)用計(jì)算相對來說是一個(gè)TemplateMethod 設(shè)計(jì)模式。


例子

舉例子說明,讓我們做一個(gè)存儲PHP參數(shù)的cache。這個(gè)cahce類需要把變量以PHP識別的方式寫入到一個(gè)文件當(dāng)中,所以你可以在以后加載該文件并使用它。這個(gè)類還應(yīng)該可以讓你為每個(gè)數(shù)據(jù)加個(gè)標(biāo)識符和存儲的方式。

數(shù)據(jù)緩存

注:緩存是為了在接下來的操作中繼續(xù)使用而對資源進(jìn)行緩存。你可以通過建立和使用緩存來節(jié)省直接從原數(shù)據(jù)庫獲取數(shù)據(jù)的時(shí)間。這方面的例子最常見的就是訪問數(shù)據(jù)庫或者解析大的XML文檔,或者大的配置文件。

緩存也會出現(xiàn)一個(gè)問題:你的緩存可能會失去與原數(shù)據(jù)的同步。或者緩存需要使用太多內(nèi)存。

最開始,我們開發(fā)一個(gè)緩存操作,并不使用策略模式。

因?yàn)槟憧赡苄枰彺娴牟恢挂粋(gè)值,所以你需要使用標(biāo)識符來標(biāo)識出你需要指定的元素。在這個(gè)例子中,標(biāo)識符就是’application_config’。下面試一個(gè)如果使用cache的例子。

// PHP4
$config_cache =& new VarCache(‘application_config’);
if ($config_cache->isValid()) {
$config = $config_cache->get();
} else {
$config = slow_expensive_function_to_get_config();
$config_cache->set($config);
}

這個(gè)代碼生成了一個(gè)新的VarCache對象存放在$config_cache變量里面。這個(gè)數(shù)據(jù)在緩存中的標(biāo)識符是 ‘application_config’。如果在緩存里面有這個(gè)數(shù)據(jù), isValid() 將返回真( true )并且獲取緩存中的數(shù)據(jù)。反之,值被重新獲取并寫入緩存當(dāng)中,以便下次使用。

按照一般的需求,讓我們開始編寫這段代碼來進(jìn)行測試。首先,如果緩存中沒有該數(shù)據(jù), isValid() 方式函數(shù)應(yīng)該返回非值(false)。

class VarCacheTestCase extends UnitTestCase {
function TestUnsetValueIsInvalid() {
$cache =& new VarCache(‘foo’);
$this->assertFalse($cache->isValid());
}

因?yàn)閂arCache現(xiàn)在沒有代碼,所以最簡單的方式就是先構(gòu)造一個(gè)方式函數(shù)。

class VarCache {
function isValid() {}
}


這樣,我們就可以繼續(xù)了。

class VarCacheTestCase extends UnitTestCase {
function TestUnsetValueIsInvalid() { /* ... */ }
function TestIsValidTrueAfterSet() {
$cache =& new VarCache(‘foo’);
$cache->set(‘bar’);
$this->assertTrue($cache->isValid());
}

上面的測試校驗(yàn)了緩存的數(shù)據(jù)是否是可用的。

開始編寫cache類的主要部分。VarCache 引入一個(gè)標(biāo)識符, 所以constructor了一個(gè)應(yīng)該記錄它的對象實(shí)例。這里面還有一個(gè)set的方式函數(shù),用來把數(shù)據(jù)存入緩存,或者當(dāng)數(shù)據(jù)存在時(shí),修改緩存當(dāng)中的數(shù)據(jù)。

class VarCache {
var $_name;
function VarCache($name) {
$this->_name = ‘cache/’.$name;
}
function isValid() {
return file_exists($this->_name.’.php’);
}
function set() {
$file_handle = fopen($this->_name.’.php’, ‘w’);
fclose($file_handle);
}
}


對象實(shí)例的參數(shù)$_name 存放了緩存的標(biāo)識符。在這個(gè)簡單的操作中, $_name 被用來生成文件名(在實(shí)際的使用可能會數(shù)據(jù)庫或者其它的數(shù)據(jù)源代替) set() 使用 fopen() 和 fclose() 來 “訪問” 基于$_name的文件。當(dāng)調(diào)用set()后, file_exists()在VarCache::isValid()里面調(diào)用返回真(true)。

運(yùn)行這個(gè)測試來產(chǎn)生一個(gè)我們預(yù)期的結(jié)果;但是實(shí)際情況是報(bào)錯(cuò)!為什么呢?第一次運(yùn)新的時(shí)候沒有生成文件,所以第二次運(yùn)行的時(shí)候找不到文件,顯然我們不希望這種情況出現(xiàn)。我們期望的是每一次運(yùn)行代碼都是互不影響的。

幸運(yùn)的是,把總體測試框架和特定功能的簡單測試結(jié)合起來,我們就可以得到靈活的測試環(huán)境,并且在以后的測試中方便地使用。UnitTestCase::setUp()實(shí)現(xiàn)框架的初始化,而UnitTestCase::tearDown()實(shí)現(xiàn)具體的測試過程。

分享:《PHP設(shè)計(jì)模式介紹》第五章 注冊模式
我們通常認(rèn)為避免使用全局變量是一種好的選擇,因此,對象經(jīng)常被作為參數(shù)從一段代碼傳遞到另一段。但是傳遞實(shí)例的一個(gè)問題就是對象有時(shí)候不知道將要傳遞給誰——?經(jīng)過一個(gè)函數(shù)后才被傳

共3頁上一頁123下一頁
來源:模板無憂//所屬分類:PHP教程/更新時(shí)間:2008-08-22
相關(guān)PHP教程