《PHP設(shè)計(jì)模式介紹》第二章 值對(duì)象模式(5)_PHP教程
推薦:《PHP設(shè)計(jì)模式介紹》第一章 編程慣用法學(xué)習(xí)一門新的語言意味著要采用新的慣用法。這章將介紹或者可能重新強(qiáng)調(diào)一些慣用法。你會(huì)發(fā)現(xiàn)這些慣用法在你要在代碼中實(shí)現(xiàn)設(shè)計(jì)模式時(shí)候是非常有用的。 在這里總結(jié)的許多編程慣用法都是很值得
PHP4樣本代碼:
和PHP5不一樣的是,PHP4賦值對(duì)象資源的時(shí)候是拷貝該對(duì)象,這個(gè)語法的特點(diǎn)本質(zhì)上和值對(duì)象設(shè)計(jì)模式要求正好吻合。
然而,PHP4不能控制的屬性和方法函數(shù)在對(duì)象之外的可見性,所以實(shí)現(xiàn)一個(gè)值對(duì)象設(shè)計(jì)模式相對(duì)PHP5也有細(xì)微的差別。
假如你回想一下這本書序言中的“對(duì)象句柄”部分,它提出了三個(gè) “規(guī)則”,當(dāng)你在PHP4中使用對(duì)象去模仿PHP5中的對(duì)象句柄時(shí),這三個(gè)規(guī)則總是適用的:
- 通過指針($obj=&new class;)來創(chuàng)建對(duì)象。
- 用指針(function funct(&$obj) param{})來傳遞對(duì)象。
- 用指針(function &some_funct() {} $returned_obj =& some_funct())來獲取一個(gè)對(duì)象。
然后,值對(duì)象設(shè)計(jì)模式卻不能使用上述三個(gè)“總是適用”的規(guī)則。只有忽視了這些規(guī)則,才能總是得到一個(gè)PHP4對(duì)象的拷貝(這相當(dāng)于PHP5中的“克隆”操作,描述在http://www.php.net/manual/en/language.oop5.cloning.php)
因?yàn)镻HP4可以輕松地賦值一個(gè)對(duì)象—這在PHP語言中是一個(gè)固有的行為,所以實(shí)現(xiàn)變量的不可更改就需要通過值對(duì)象通用協(xié)定來實(shí)現(xiàn)。在PHP4中,如果要使用值對(duì)象,請(qǐng)不要通過指針來創(chuàng)建或獲取一個(gè)對(duì)象,并且給所有需要保護(hù)以免外界修改的屬性或者方法函數(shù)命名時(shí),都在屬性和方法函數(shù)的名字加上下劃線(_)做前綴。按照協(xié)定,變量如果具有值對(duì)象的屬性,應(yīng)該使用一個(gè)下劃線來標(biāo)識(shí)它的私有性。
下面是PHP4中的Dollar類:
下面這個(gè)實(shí)例可以說明,你不能在PHP4中限制一個(gè)屬性只能被外部更改:
function TestChangeAmount() {
$d = new Dollar(5);
$this->assertEqual(5, $d->getAmount());
//only possible in php4 by not respecting the _private convention
$d->_amount = 10;
$this->assertEqual(10, $d->getAmount());
}
再重復(fù)一次,在所有PHP4對(duì)象中,私有變量的前綴使用一個(gè)下劃線,但是你還是可以從外部來直接訪問私有屬性和方法函數(shù)。
值對(duì)象中的商業(yè)邏輯
值對(duì)象(Value Objects)不僅僅用于最小限度的訪問方法這樣的簡單的數(shù)據(jù)結(jié)構(gòu),它同樣還可以包括有價(jià)值的商業(yè)邏輯�?紤]以下你如果實(shí)現(xiàn)許多人中平均分配金錢。
如果總錢數(shù)確實(shí)是可以分成整數(shù),你可以生成一組Dollar對(duì)象,而且每一個(gè)Dollar對(duì)象都擁有相同的部分。但是當(dāng)總數(shù)可以整數(shù)的美元或者美分的時(shí)候,我們?cè)撛趺刺幚砟兀?/p>
讓我們開始用一個(gè)簡單的代碼來測試一下:
// PHP5
function testDollarDivideReturnsArrayOfDivisorSize() {
$full_amount = new Dollar(8);
$parts = 4;
$this->assertIsA(
$result = $full_amount->divide($parts)
,’array’);
$this->assertEqual($parts, count($result));
}
注釋 assertIsA:
assertIsA()的作用是讓你測試:一個(gè)特定的變量是否屬于一個(gè)實(shí)例化的類。當(dāng)然你也可以用它來驗(yàn)證變量是否屬于一些php類型:字符串、數(shù)字、數(shù)組等。
為了實(shí)現(xiàn)上述測試, Dollar::divide()方法函數(shù)的編碼如下…
public function divide($divisor) {
return array_fill(0,$divisor,null);
}
最好加上更多的細(xì)節(jié)。
function testDollarDrivesEquallyForExactMultiple() {
$test_amount = 1.25;
$parts = 4;
$dollar = new Dollar($test_amount*$parts);
foreach($dollar->divide($parts) as $part) {
$this->assertIsA($part, ‘Dollar’);
$this->assertEqual($test_amount, $part->getAmount());
}
}
現(xiàn)在,應(yīng)當(dāng)返回存有正確數(shù)據(jù)的Dollar對(duì)象,而不是簡單的返回?cái)?shù)量正確的數(shù)組。
實(shí)現(xiàn)這個(gè)仍然只需要一行語句:
最后一段代碼需要解決一個(gè)除數(shù)不能把Dollar的總數(shù)均勻的除開的問題。
這是一個(gè)棘手的問題:如果存在不能均勻除開的情況,是第一部分還是最后一部分能得到一個(gè)額外的金額(便士)?怎樣獨(dú)立測試這部分的代碼?
一個(gè)方法是:明確指定代碼最后需要實(shí)現(xiàn)目標(biāo):這個(gè)數(shù)組的元素?cái)?shù)量應(yīng)該是與除數(shù)表示的數(shù)量相等的,數(shù)組的元素之間的差異不能大于0.01,并且所有部分的總數(shù)應(yīng)該與被除之前的總數(shù)的值是相等的。
上面的描述通過正如下面的代碼實(shí)現(xiàn):
function testDollarDivideImmuneToRoundingErrors() {
$test_amount = 7;
$parts = 3;
$this->assertNotEqual( round($test_amount/$parts,2),
$test_amount/$parts,
’Make sure we are testing a non-trivial case %s’);
$total = new Dollar($test_amount);
$last_amount = false;
$sum = new Dollar(0);
foreach($total->divide($parts) as $part) {
if ($last_amount) {
$difference = abs($last_amount-$part->getAmount());
$this->assertTrue($difference <= 0.01);
}
$last_amount = $part->getAmount();
$sum = $sum->add($part);
}
$this->assertEqual($sum->getAmount(), $test_amount);
}
注釋 assertNotEqual:
當(dāng)你要確保兩個(gè)變量的值是不相同時(shí),你可以用它來進(jìn)行檢驗(yàn)。這里面的值相同是PHP的”==”運(yùn)算符進(jìn)行判斷的。任何情況下當(dāng)你需要確保兩個(gè)變量的值是不相同的時(shí)候,你就可以使用它。
現(xiàn)在根據(jù)上述代碼,如果來構(gòu)造Dollar::divide()方法函數(shù)呢?
|
class Dollar { |
解決上邊這些問題的方法是什么呢?還是使用測試導(dǎo)向的開發(fā)循環(huán)模式:增加一個(gè)需求實(shí)例,觀察可能的錯(cuò)誤,編寫代碼來生成一個(gè)新的實(shí)例進(jìn)行運(yùn)行,還有問題存在時(shí)繼續(xù)分解。最后重復(fù)上述過程。
|
public function divide($divisor) { return array_fill(0,$divisor,new Dollar($this->amount / $divisor)); |
| // PHP4 class Dollar { var $_amount; function Dollar($amount=0) { $this->_amount = (float)$amount; } function getAmount() { return $this->_amount; } function add($dollar) { return new Dollar($this->_amount $dollar->getAmount()); } function debit($dollar) { return new Dollar($this->_amount - $dollar->getAmount()); } } |
分享:《PHP設(shè)計(jì)模式介紹》導(dǎo)言當(dāng)你在不斷的試圖從你的應(yīng)用程序中發(fā)現(xiàn)新的特征時(shí),你是否發(fā)現(xiàn)你提出的解決方法和一些以前你已經(jīng)實(shí)現(xiàn)的東西是如此的類似呢?如果你是一個(gè)程序員(即使你才 開始很短的時(shí)間),你都可能回答&ldqu
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁面代碼執(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的匹配多國語言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
PHP教程Rss訂閱編程教程搜索
PHP教程推薦
- php仿QQ驗(yàn)證碼的實(shí)例分析
- 解決FastCGI 進(jìn)程超過了配置的活動(dòng)超時(shí)時(shí)限的問題
- 你或許尚未了解PHP的那10件事情
- 詳解PHP內(nèi)置訪問資源的超時(shí)時(shí)間 time_out file_get_contents read_file
- 做了CDN獲取用戶真實(shí)IP的函數(shù)代碼(PHP與Asp設(shè)置方式)
- 解決PHP無法訪問遠(yuǎn)程mysql的問題
- 用什么軟件打開php文件
- PHP技巧:PHP腳本中關(guān)于拼寫檢查函數(shù)庫
- 解析PHP編寫的25個(gè)游戲腳本
- PHP命名空間(Namespace)的使用詳解
- 相關(guān)鏈接:
- 教程說明:
PHP教程-《PHP設(shè)計(jì)模式介紹》第二章 值對(duì)象模式(5)
。