php設(shè)計(jì)模式介紹之值對(duì)象模式(5)_PHP教程

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

      推薦:談PHP程序開發(fā)中的中文編碼問(wèn)題
      PHP程序設(shè)計(jì)中中文編碼問(wèn)題曾經(jīng)困擾很多人,導(dǎo)致這個(gè)問(wèn)題的原因其實(shí)很簡(jiǎn)單,每個(gè)國(guó)家(或區(qū)域)都規(guī)定了計(jì)算機(jī)信息交換用的字符編碼集,如美國(guó)的擴(kuò)展 ASCII 碼, 中國(guó)的 GB2312-80,日本的 JIS 等。作為該國(guó)家/區(qū)域內(nèi)信息處理的基礎(chǔ),字符編碼集起著統(tǒng)一編碼的

      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è)撛趺刺幚砟兀?/p>

      讓我們開始用一個(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ò)程。

      分享:淺談?wù)_理解PHP程序錯(cuò)誤信息的表示含義
      簡(jiǎn)述:我們編寫程序時(shí),無(wú)論怎樣小心謹(jǐn)慎,犯錯(cuò)總是在所難免的。這些錯(cuò)誤通常會(huì)迷惑PHP編譯器。如果開發(fā)人員無(wú)法了解編譯器報(bào)錯(cuò)信息的含義,那么這些錯(cuò)誤信息不僅毫無(wú)用處,還會(huì)常常讓人感到沮喪。 我們編寫程序時(shí),無(wú)論怎樣小心謹(jǐn)慎,犯錯(cuò)總是在所難免的。

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