日韩天天综合网_野战两个奶头被亲到高潮_亚洲日韩欧美精品综合_av女人天堂污污污_视频一区**字幕无弹窗_国产亚洲欧美小视频_国内性爱精品在线免费视频_国产一级电影在线播放_日韩欧美内地福利_亚洲一二三不卡片区

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

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

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

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

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

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

問(wèn)題

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

解決辦法

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

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

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

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


例子

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

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

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

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

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

因?yàn)槟憧赡苄枰彺娴牟恢挂粋(gè)值,所以你需要使用標(biāo)識(shí)符來(lái)標(biāo)識(shí)出你需要指定的元素。在這個(gè)例子中,標(biāo)識(shí)符就是’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對(duì)象存放在$config_cache變量里面。這個(gè)數(shù)據(jù)在緩存中的標(biāo)識(shí)符是 ‘application_config’。如果在緩存里面有這個(gè)數(shù)據(jù), isValid() 將返回真( true )并且獲取緩存中的數(shù)據(jù)。反之,值被重新獲取并寫入緩存當(dāng)中,以便下次使用。

按照一般的需求,讓我們開始編寫這段代碼來(lái)進(jìn)行測(cè)試。首先,如果緩存中沒有該數(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)在沒有代碼,所以最簡(jiǎ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());
}

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

開始編寫cache類的主要部分。VarCache 引入一個(gè)標(biāo)識(shí)符, 所以constructor了一個(gè)應(yīng)該記錄它的對(duì)象實(shí)例。這里面還有一個(gè)set的方式函數(shù),用來(lái)把數(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);
}
}


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

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

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

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

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