例如:通常用一個(gè)對(duì)象描述一個(gè)日期、一個(gè)數(shù)字或者貨幣。日期、整數(shù)或美元的類定義是都是便于使用的、快捷、便于封裝的,并且方便進(jìn)行拷貝,相互比較,甚至是創(chuàng)建。
從表面上看,這些描述簡(jiǎn)單的對(duì)象很容易被執(zhí)行:它們的語(yǔ)句非常少,在構(gòu)造類時(shí)無(wú)論是應(yīng)用于Customer還是SKU都沒有什么不同。這個(gè)想法似乎是正確的,但是所謂的"似乎正確"很容易產(chǎn)生一些bug。
請(qǐng)看下面的代碼,這是一個(gè)關(guān)于以美元給員工發(fā)放工資的對(duì)象的定義和執(zhí)行操作。多數(shù)情況下,它的運(yùn)行是沒有問(wèn)題的。(這個(gè)類被命名為BadDollar,因?yàn)樗€存在著bug)。考慮一下,看你是否能發(fā)現(xiàn)它的bug。
// PHP5
class BadDollar {
protected $amount;
public function __construct($amount=0) {
$this->amount = (float)$amount;
}
public function getAmount() {
return $this->amount;
}
public function add($dollar) {
$this->amount += $dollar->getAmount();
}
}
class Work {
protected $salary;public function __construct() {
$this->salary = new BadDollar(200);}
public function payDay() {
return $this->salary;
}
}
class Person {
public $wallet;
}
function testBadDollarWorking() {
$job = new Work;
$p1 = new Person;
$p2 = new Person;
$p1->wallet = $job->payDay();
$this->assertEqual(200, $p1->wallet->getAmount());
$p2->wallet = $job->payDay();
$this->assertEqual(200, $p2->wallet->getAmount());
$p1->wallet->add($job->payDay());
$this->assertEqual(400, $p1->wallet->getAmount());
//this is bad — actually 400
$this->assertEqual(200, $p2->wallet->getAmount());
//this is really bad — actually 400
$this->assertEqual(200, $job->payDay()->getAmount());
}
那么, bug是什么呢?如果不能上面的代碼例子中直觀地發(fā)現(xiàn)問(wèn)題,這里有個(gè)提示:雇員對(duì)象$p1和對(duì)象$p2使用著同一個(gè)BadDollar對(duì)象實(shí)例。
首先,類Work和類Person的實(shí)例已經(jīng)創(chuàng)建。那么,假設(shè)每一個(gè)雇員最初有一個(gè)空的電子錢包,雇員的電子錢包Person:wallet是通過(guò)Work::payDay()函數(shù)返回的對(duì)象資源變量賦值的,所以被設(shè)定為一個(gè)BadDollar類的對(duì)象實(shí)例。
還記得PHP5的對(duì)象賦值處理方式嗎?因?yàn)镻HP5的對(duì)象賦值的處理方式,所以$job::salary,、$p1::wallet和$p2::wallet這三個(gè)看上去不同的對(duì)象實(shí)例雖然使用著不同的“標(biāo)識(shí)符”,但是事實(shí)上,它們?nèi)慷贾付ǖ酵粋€(gè)對(duì)象實(shí)例。
因此,接下來(lái)的發(fā)放工資的操作(PayDay表示發(fā)放工資的日子,這里表示發(fā)放工資的動(dòng)作),使用$job->payDay()本來(lái)僅僅是想增加$P1的工資,卻出乎意料地次給$P2也發(fā)放了。并且,這個(gè)動(dòng)作還改變了工作的基本工資的額度。因此,最后兩個(gè)值的檢測(cè)報(bào)錯(cuò)。
Value Object PHP5 Unit Test
1) Equal expectation fails because [Integer: 200] differs from [Float: 400] by 200
in testBadDollarWorking
in ValueObjTestCase
2) Equal expectation fails because [Integer: 200] differs from [Float: 400] by 200
in testBadDollarWorking
in ValueObjTestCase
FAILURES!!!
問(wèn)題:
那么,你該如何為Date或Dollar這樣一些描述簡(jiǎn)單的應(yīng)用定義一個(gè)高效的類,并且易于創(chuàng)建呢。
解決方案:
高效的對(duì)象應(yīng)該像PHP的整型那樣運(yùn)作:如果你把同一個(gè)對(duì)象資源賦值給兩個(gè)不同的變量,然后改變其中的一個(gè)變量,另一個(gè)變量仍然不受影響。事實(shí)上,這就是Value Object模式的目標(biāo)所在。
執(zhí)行Value Object時(shí),php4和php5是有區(qū)別的。
正如以上你所看到的,PHP5通過(guò)new進(jìn)行對(duì)象資源的賦值傳遞的是對(duì)象資源的指針就像我們?cè)赑HP4中通過(guò)指針傳遞一樣。很明顯,這是一個(gè)問(wèn)題。為了解決那個(gè)問(wèn)題并實(shí)現(xiàn)一個(gè)專有對(duì)象Dollar的值,我們必須使屬性$amount的對(duì)象的所有屬性的一個(gè)值在一般情況下不可變或不能改變。但是在PHP語(yǔ)言的沒有提供參數(shù)不可改變的功能的情況下,你完全可以結(jié)合屬性的可見性與獲得和設(shè)置方法來(lái)實(shí)現(xiàn)。
相反地,PHP4操作所有的對(duì)象都是遵循Value Objects對(duì)象規(guī)律的,因?yàn)镻HP4的賦值操作相當(dāng)于對(duì)對(duì)象做了一個(gè)拷貝。所以為了在PHP4中實(shí)現(xiàn)Value Objects設(shè)計(jì)模式你需要打破你細(xì)心地培養(yǎng)的通過(guò)指針賦值來(lái)創(chuàng)建、傳遞、提取對(duì)象的習(xí)慣。
注:術(shù)語(yǔ) 不可變的(Immutable):
在詞典中Immutable的定義是不允許或不易受影響。在編程中,這個(gè)術(shù)語(yǔ)表示一個(gè)一旦被設(shè)置就不能改變的值。
PHP5 樣本代碼:
既然我們開始用PHP5編寫代碼,讓我們優(yōu)化一個(gè)PHP5的Value Object的實(shí)例并創(chuàng)建一個(gè)較好的Dollar類定義。命名在面向?qū)ο缶幊讨蟹浅V匾x擇一個(gè)唯一的貨幣類型作為這個(gè)類的名字,說(shuō)明它不被定義為可以處理多種貨幣類型的類。
class Dollar {
protected $amount;
public function __construct($amount=0) {
$this->amount = (float)$amount;
}
public function getAmount() {
return $this->amount;
}
public function add($dollar) {
return new Dollar($this->amount + $dollar->getAmount());
}
}
類里面的屬性如果加上protected前綴,別的類是訪問(wèn)不了的。protected(和private)拒絕通過(guò)屬性直接被訪問(wèn)。
通常,當(dāng)你使用面向?qū)ο筮M(jìn)行編程的時(shí)候,你經(jīng)常需要?jiǎng)?chuàng)建了一個(gè)“setter”函數(shù),就類似于:
public setAmount($amount)
{
$this->amount=$amount;
}
一樣,在這種情況下,雖然沒有設(shè)定函數(shù)Dollar::amount(),但在對(duì)象的實(shí)例化期時(shí),參數(shù)Dollar::amount就已經(jīng)被賦值了。而函數(shù)Dollar::getAmount()只是提供一個(gè)訪問(wèn)Dollar屬性的功能,在這里訪問(wèn)的數(shù)據(jù)類型為浮點(diǎn)型。
最有趣的變化是在Dollar::add()方法函數(shù)中。并不是直接改變$this->amount變量的值從而會(huì)改變已存在的Dollar對(duì)象實(shí)例,而是創(chuàng)建并返回一個(gè)新的Dollar實(shí)例。現(xiàn)在,盡管你指定當(dāng)前對(duì)象給多個(gè)變量,但是每一個(gè)變量的變化都不會(huì)影響其它的變量實(shí)例。
對(duì)于價(jià)值設(shè)計(jì)模式不變性是關(guān)鍵,任何對(duì)于一個(gè)Value Object的變量amount的改變,是通過(guò)創(chuàng)建一個(gè)新的帶有不同預(yù)期值的類的實(shí)例來(lái)完成的。上文中提高的最初那個(gè)$this->amount變量的值從未改變。
簡(jiǎn)單來(lái)說(shuō),在PHP5里面使用價(jià)值設(shè)計(jì)模式時(shí),需要注意以下幾個(gè)方面:
保護(hù)值對(duì)象的屬性,禁止被直接訪問(wèn)。
在構(gòu)造函數(shù)中就對(duì)屬性進(jìn)行賦值。
去掉任何一個(gè)會(huì)改變屬性值的方式函數(shù)(setter),否則屬性值很容易被改變。
以上三步創(chuàng)建了一個(gè)不變的值,這個(gè)值一旦被初始化設(shè)置之后就不能被改變。當(dāng)然,你也應(yīng)該提供一個(gè)查看函數(shù)或者是訪問(wèn)Value Object的屬性的方法,并且可以添加一些與這個(gè)類相關(guān)的函數(shù)。值對(duì)象并不是只能用在一個(gè)簡(jiǎn)單的架構(gòu)上,它也可以實(shí)現(xiàn)重要的商務(wù)邏輯應(yīng)用。讓我們看看下一個(gè)例子:
詳細(xì)例子:
讓我們?cè)谝幌赂訌?fù)雜的例子中查看值對(duì)象模式的功能。
讓我們開始實(shí)現(xiàn)一個(gè)的基于PHP5中Dollar類中的一個(gè)Monopoly游戲。
第一個(gè)類Monopoly的框架如下:
class Monopoly {
protected $go_amount;
/**
* game constructor
* @return void
*/
public function __construct() {
$this->go_amount = new Dollar(200);
}
/**
* pay a player for passing 揋o?/span>
* @param Player $player the player to pay
* @return void
*/
public function passGo($player) {
$player->collect($this->go_amount);
}
}
目前,Monopoly的功能比較簡(jiǎn)單。構(gòu)造器創(chuàng)建一個(gè)Dollar類的實(shí)例$go_amount,設(shè)定為200,實(shí)例go_amount常常被passtGo()函數(shù)調(diào)用,它帶著一個(gè)player參數(shù),并讓對(duì)象player的函數(shù)collect為player機(jī)上200美元.
Player類的聲明請(qǐng)看下面代碼,Monoplay類調(diào)用帶一個(gè)Dollar參數(shù)的Player::collect()方法。然后把Dollar的數(shù)值加到Player的現(xiàn)金余額上。另外,通過(guò)判斷Player::getBalance()方法函數(shù)返回來(lái)的余額,我們可以知道使訪問(wèn)當(dāng)前Player和Monopoly對(duì)象實(shí)例是否在工作中。
class Player {
protected $name;
protected $savings;
/**
* constructor
* set name and initial balance
* @param string $name the players name
* @return void
*/
public function __construct($name) {
$this->name = $name;
$this->savings = new Dollar(1500);
}
/**
* receive a payment
* @param Dollar $amount the amount received
* @return void
*/
public function collect($amount) {
$this->savings = $this->savings->add($amount);
}
* return player balance
* @return float
*/
public function getBalance() {
return $this->savings->getAmount();
}
}
上邊已經(jīng)給出了一個(gè)Monopoly和Player類,你現(xiàn)在可以根據(jù)目前聲明的幾個(gè)類定義進(jìn)行一些測(cè)試了。
MonopolyTestCase的一個(gè)測(cè)試實(shí)例可以像下面這樣寫:
class MonopolyTestCase extends UnitTestCase {
function TestGame() {
$game = new Monopoly;
$player1 = new Player(‘Jason');
$this->assertEqual(1500, $player1->getBalance());
$game->passGo($player1);
$this->assertEqual(1700, $player1->getBalance());
$game->passGo($player1);
$this->assertEqual(1900, $player1->getBalance());
}
}
如果你運(yùn)行MonopolyTestCase這個(gè)測(cè)試代碼,代碼的運(yùn)行是沒有問(wèn)題的。現(xiàn)在可以添加一些新的功能。
另一個(gè)重要的概念是對(duì)象Monopoly中的租金支付。讓我們首先寫一個(gè)測(cè)試實(shí)例(測(cè)試引導(dǎo)開發(fā))。下面的代碼希望用來(lái)實(shí)現(xiàn)既定的目標(biāo)。
function TestRent() {
$game = new Monopoly;
$player1 = new Player(‘Madeline');
$player2 = new Player(‘Caleb');
$this->assertEqual(1500, $player1->getBalance());
$this->assertEqual(1500, $player2->getBalance());
$game->payRent($player1, $player2, new Dollar(26));
$this->assertEqual(1474, $player1->getBalance());
$this->assertEqual(1526, $player2->getBalance());
}
根據(jù)這個(gè)測(cè)試代碼,我們需要在Monopoly對(duì)象中增加payRent()的方法函數(shù)來(lái)實(shí)現(xiàn)一個(gè)Player對(duì)象去支付租金給另一個(gè)Player對(duì)象.
Class Monopoly {
// ...
/**
* pay rent from one player to another
* @param Player $from the player paying rent
* @param Player $to the player collecting rent
* @param Dollar $rent the amount of the rent
* @return void
*/
public function payRent($from, $to, $rent) {
$to->collect($from->pay($rent));
}
}
payRent()方法函數(shù)實(shí)現(xiàn)了兩個(gè)player對(duì)象之間($from和$to)的租金支付。方法函數(shù)Player::collect()已經(jīng)被定義了,但是Player::pay()必須被添加進(jìn)去,以便實(shí)例$from通過(guò)pay()方法支付一定的Dollar數(shù)額$to對(duì)象中。首先我們定義Player::pay()為:
class Player {
// ...
public function pay($amount) {
$this->savings = $this->savings->add(-1 * $amount);
}
}
但是,我們發(fā)現(xiàn)在PHP中你不能用一個(gè)數(shù)字乘以一個(gè)對(duì)象(不像其他語(yǔ)言,PHP不允許重載操作符,以便構(gòu)造函數(shù)進(jìn)行運(yùn)算)。所以,我們通過(guò)添加一個(gè)debit()方法函數(shù)實(shí)現(xiàn)Dollar對(duì)象的減的操作。
class Dollar {
protected $amount;
public function __construct($amount=0) {
$this->amount = (float)$amount;
}
public function getAmount() {
return $this->amount;
}
public function add($dollar) {
return new Dollar($this->amount + $dollar->getAmount());
}
public function debit($dollar) {
return new Dollar($this->amount - $dollar->getAmount());
}
}
引入Dollar::debit()后,Player::pay()函數(shù)的操作依然是很簡(jiǎn)單的。
class Player {
// ...
/**
* make a payment
* @param Dollar $amount the amount to pay
* @return Dollar the amount payed
*/
public function pay($amount) {
$this->savings = $this->savings->debit($amount);
return $amount;
}
}
Player::pay()方法返回支付金額的$amount對(duì)象,所以Monopoly::payRent()中的語(yǔ)句$to->collect($from->pay($rent))的用法是沒有問(wèn)題的。這樣做的話,如果將來(lái)你添加新的“商業(yè)邏輯”用來(lái)限制一個(gè)player不能支付比他現(xiàn)有的余額還多得金額。(在這種情況下,將返回與player的賬戶余額相同的數(shù)值。同時(shí),也可以調(diào)用一個(gè)“破產(chǎn)異常處理”來(lái)計(jì)算不足的金額,并進(jìn)行相關(guān)處理。對(duì)象$to仍然從對(duì)象$from中取得$from能夠給予的金額。)
注:術(shù)語(yǔ)------商業(yè)邏輯
在一個(gè)游戲平臺(tái)的例子上提及的“商業(yè)邏輯”似乎無(wú)法理解。這里的商業(yè)的意思并不是指正常公司的商業(yè)運(yùn)作,而是指因?yàn)樘厥鈶?yīng)用領(lǐng)域需要的概念。請(qǐng)把它認(rèn)知為 “一個(gè)直接的任務(wù)或目標(biāo)”,而不是“這里面存在的商業(yè)操作”。
所以,既然目前我們討論的是一個(gè)Monopoly,那么這里的 “商業(yè)邏輯”蘊(yùn)含的意思就是針對(duì)一個(gè)游戲的規(guī)則而說(shuō)的。
PHP4樣本代碼:
和PHP5不一樣的是,PHP4賦值對(duì)象資源的時(shí)候是拷貝該對(duì)象,這個(gè)語(yǔ)法的特點(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ī)則總是適用的:
通過(guò)指針($obj=&new class;)來(lái)創(chuàng)建對(duì)象。
用指針(function funct(&$obj) param{})來(lái)傳遞對(duì)象。
用指針(function &some_funct() {} $returned_obj =& some_funct())來(lái)獲取一個(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語(yǔ)言中是一個(gè)固有的行為,所以實(shí)現(xiàn)變量的不可更改就需要通過(guò)值對(duì)象通用協(xié)定來(lái)實(shí)現(xiàn)。在PHP4中,如果要使用值對(duì)象,請(qǐng)不要通過(guò)指針來(lái)創(chuàng)建或獲取一個(gè)對(duì)象,并且給所有需要保護(hù)以免外界修改的屬性或者方法函數(shù)命名時(shí),都在屬性和方法函數(shù)的名字加上下劃線(_)做前綴。按照協(xié)定,變量如果具有值對(duì)象的屬性,應(yīng)該使用一個(gè)下劃線來(lái)標(biāo)識(shí)它的私有性。
下面是PHP4中的Dollar類:
// 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());
}
}
下面這個(gè)實(shí)例可以說(shuō)明,你不能在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è)下劃線,但是你還是可以從外部來(lái)直接訪問(wèn)私有屬性和方法函數(shù)。
值對(duì)象中的商業(yè)邏輯
值對(duì)象(Value Objects)不僅僅用于最小限度的訪問(wèn)方法這樣的簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu),它同樣還可以包括有價(jià)值的商業(yè)邏輯。考慮以下你如果實(shí)現(xiàn)許多人中平均分配金錢。
如果總錢數(shù)確實(shí)是可以分成整數(shù),你可以生成一組Dollar對(duì)象,而且每一個(gè)Dollar對(duì)象都擁有相同的部分。但是當(dāng)總數(shù)可以整數(shù)的美元或者美分的時(shí)候,我們?cè)撛趺刺幚砟兀?nbsp;
讓我們開始用一個(gè)簡(jiǎn)單的代碼來(lái)測(cè)試一下:
// 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()的作用是讓你測(cè)試:一個(gè)特定的變量是否屬于一個(gè)實(shí)例化的類。當(dāng)然你也可以用它來(lái)驗(yàn)證變量是否屬于一些php類型:字符串、數(shù)字、數(shù)組等。
為了實(shí)現(xiàn)上述測(cè)試, 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ì)象,而不是簡(jiǎn)單的返回?cái)?shù)量正確的數(shù)組。
實(shí)現(xiàn)這個(gè)仍然只需要一行語(yǔ)句:
public function divide($divisor) {
return array_fill(0,$divisor,new Dollar($this->amount / $divisor));
最后一段代碼需要解決一個(gè)除數(shù)不能把Dollar的總數(shù)均勻的除開的問(wèn)題。
這是一個(gè)棘手的問(wèn)題:如果存在不能均勻除開的情況,是第一部分還是最后一部分能得到一個(gè)額外的金額(便士)?怎樣獨(dú)立測(cè)試這部分的代碼?
一個(gè)方法是:明確指定代碼最后需要實(shí)現(xiàn)目標(biāo):這個(gè)數(shù)組的元素?cái)?shù)量應(yīng)該是與除數(shù)表示的數(shù)量相等的,數(shù)組的元素之間的差異不能大于0.01,并且所有部分的總數(shù)應(yīng)該與被除之前的總數(shù)的值是相等的。
上面的描述通過(guò)正如下面的代碼實(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í),你可以用它來(lái)進(jìn)行檢驗(yàn)。這里面的值相同是PHP的”==”運(yùn)算符進(jìn)行判斷的。任何情況下當(dāng)你需要確保兩個(gè)變量的值是不相同的時(shí)候,你就可以使用它。
現(xiàn)在根據(jù)上述代碼,如果來(lái)構(gòu)造Dollar::divide()方法函數(shù)呢?
class Dollar {
protected $amount;
public function __construct($amount=0) {
$this->amount = (float)$amount;
}
public function getAmount() {
return $this->amount;
}
public function add($dollar) {
return new Dollar($this->amount + $dollar->getAmount());
}
public function debit($dollar) {
return new Dollar($this->amount - $dollar->getAmount());
}
public function divide($divisor) {
$ret = array();
$alloc = round($this->amount / $divisor,2);
$cumm_alloc = 0.0;
foreach(range(1,$divisor-1) as $i) {
$ret[] = new Dollar($alloc);
$cumm_alloc += $alloc;
}
$ret[] = new Dollar(round($this->amount - $cumm_alloc,2));
return $ret;
}
}
這段代碼可以正常運(yùn)行,但是仍然有一些問(wèn)題,考慮一下如果在testDollarDivide()的開始處改變$test_amount 為 0.02; $num_parts 為 5;這樣的臨界條件,或者考慮一下當(dāng)你的除數(shù)不是一個(gè)整型數(shù)字,你該怎么做?
解決上邊這些問(wèn)題的方法是什么呢?還是使用測(cè)試導(dǎo)向的開發(fā)循環(huán)模式:增加一個(gè)需求實(shí)例,觀察可能的錯(cuò)誤,編寫代碼來(lái)生成一個(gè)新的實(shí)例進(jìn)行運(yùn)行,還有問(wèn)題存在時(shí)繼續(xù)分解。最后重復(fù)上述過(guò)程。
php設(shè)計(jì)模式介紹之值對(duì)象模式
2019-10-28 13:32php教程網(wǎng) PHP教程
在所有的最簡(jiǎn)單的程序中,大多數(shù)對(duì)象都有一個(gè)標(biāo)識(shí),一個(gè)重要的商業(yè)應(yīng)用對(duì)象,例如一個(gè)Customer或者一個(gè)SKU,有一個(gè)或者更多的屬性---id,name,email地址,這樣可以把它從同一個(gè)類的其他實(shí)例區(qū)分開來(lái)。此外,對(duì)象有一個(gè)恒定的標(biāo)識(shí)
延伸 · 閱讀
- 2022-03-10簡(jiǎn)單談?wù)刢entos7中配置php
- 2022-03-10JavaScript設(shè)計(jì)模式學(xué)習(xí)之代理模式
- 2022-03-10JavaScript設(shè)計(jì)模式之職責(zé)鏈模式
- 2022-03-10JavaScript設(shè)計(jì)模式之命令模式
- 2022-03-06Ubuntu14.04服務(wù)器環(huán)境下配置PHP7.0+Apache2+Mysql5.7的方
- 2022-03-05centos yum php 7.x 無(wú)需刪除升級(jí)的方法
- PHP教程
PHP變量的定義、可變變量、變量引用、銷毀方法
這篇文章主要介紹了PHP變量的定義、可變變量、變量引用、銷毀方法,需要的朋友可以參考下 ...
- PHP教程
PHP中讀取文件的8種方法和代碼實(shí)例
這篇文章主要介紹了PHP中讀取文件的8種方法和代碼實(shí)例,本文總結(jié)了PHP中讀取文件的8個(gè)函數(shù),每一個(gè)都附有使用例子及注意事項(xiàng)等,需要的朋友可以參考下...
- PHP教程
php學(xué)習(xí)之?dāng)?shù)據(jù)類型之間的轉(zhuǎn)換介紹
php學(xué)習(xí)之?dāng)?shù)據(jù)類型之間的轉(zhuǎn)換介紹,學(xué)習(xí)php的朋友可以參考下。 ...
- PHP教程
php實(shí)現(xiàn)的支持imagemagick及gd庫(kù)兩種處理的縮略圖生成類
這篇文章主要介紹了php實(shí)現(xiàn)的支持imagemagick及gd庫(kù)兩種處理的縮略圖生成類,包含了用法的詳細(xì)描述,非常實(shí)用,需要的朋友可以參考下...
- PHP教程
php學(xué)習(xí)筆記 數(shù)組的常用函數(shù)
只要一個(gè)變量,需要在多個(gè)方法使用,就將這個(gè)變量聲明為成員屬性,可以直接在這個(gè)對(duì)象中的所有方法中使用 成員屬性,相當(dāng)于這個(gè)對(duì)象中的全局變量...
- PHP教程
php全角字符轉(zhuǎn)換為半角函數(shù)
這篇文章主要介紹了PHP全角半角轉(zhuǎn)換函數(shù),把目前能找到的所有全角都列出來(lái)了一個(gè)個(gè)替換吧,需要的朋友可以參考下 ...
- PHP教程
PHP常量DIRECTORY_SEPARATOR原理及用法解析
這篇文章主要介紹了PHP常量DIRECTORY_SEPARATOR原理及用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友...
- PHP教程
php htmlentities()函數(shù)的定義和用法
下面小編就為大家?guī)?lái)一篇php htmlentities()函數(shù)的定義和用法。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧...