在 PHP 中養成 7 個面向對象的好習慣

7 個優秀 PHP OO 習慣包括:

  1. 保持謙虛。---->良好的封裝
  2. 做個好鄰居。---->正確處理錯誤,對調用者提供錯誤標示
  3. 避免看到美杜莎。----->接口的好處
  4. 利用最弱的鏈接。----->降低類之間的耦合
  5. 您是橡皮;我是膠水。----->增強類的內聚力
  6. 限制傳播。------>防止黏貼和複製,善用類的繼承
  7. 考慮使用模式

  1. 保持謙虛

  面向對象中很重要的一點就是信息的隱藏——封裝。PHP的面向對象給開發者帶來靈活性的同時也給很多的初學者帶來了不規範性。我們在開發的過程中當要用到類中的信息時,我們通常就直接操作對象的屬性來取得或者設置其值。還有我們很習慣在類的函數中臨時創建類屬性。這些都不是好習慣。

    直接公開公共字段是一個壞習慣。原因有很多,最重要的原因是讓你在實現更改中沒有應有的選擇。使用 OO 概念隔離更改,而封裝在確保所作更改在本質上不是病毒性(viral)更改方面扮演不可或缺的角色。病毒性 更改是開始時很小的更改 — 如將保存三個元素的數組更改爲一個只包含兩個元素的數組。突然,您發現需要更改越來越多的代碼以適應本應十分微不足道的更改。

   壞習慣:公開公共字段  

   清單 1. 公開公共字段的壞習慣


如果對象有任何更改,則使用該對象的所有代碼也都需要更改。例如,如果某人的教名、姓氏和其他名字被封裝到 PersonName 對象中,則需要修改所有代碼以適應更改。
好習慣:使用公共訪問方法
清單 2. 使用公共訪問方法的好習慣


    乍看之下,這段代碼可能會完成大量工作,並且實際上可能更多是在前端的工作。但是,通常,使用優秀的 OO 習慣從長遠來看十分划算,因爲將極大地鞏固未來更改。

在清單 3 中所示的代碼版本中,我已經更改了內部實現以使用名稱部件的關聯數組。比較理想的情況是,我希望擁有錯誤處理並且更仔細地檢查元素是否存在,但是本例的目 的在於展示使用我的類的代碼無需更改的程度 — 代碼並沒有察覺到類發生更改。記住採用 OO 習慣的原因是要謹慎封裝更改,這樣代碼將更具有可擴展性並且更容易維護。

  清單 3. 使用不同內部實現的另一個示例


2.做個好鄰居

  在構建類時,它應當正確地處理自己的錯誤。如果該類不知道如何處理錯誤,則應當以其調用者理解的格式封裝這些錯誤。此外,避免返回空對象或者狀態無效的對 象。許多時候,只需通過檢驗參數並拋出特定異常說明提供參數無效的原因就可以實現這一點。在您養成這個習慣時,它可以幫您 — 和維護代碼或使用對象的人員 — 節省很多時間。

   壞習慣:不處理錯誤

考慮清單 4 中所示的示例,該示例將接受一些參數並返回填充了一些值的 Person 對象。但是,在 parsePersonName() 方法中,沒有驗證提供的 $val 變量是否爲空、是否是零長度字符串或者字符串是否使用無法解析的格式。parsePersonName() 方法不返回 Person 對象,但是返回 null。使用這種方法的管理員或程序員可能會覺得很麻煩 — 至少他們現在需要開始設置斷點並調試 PHP 腳本。

  清單 4. 不拋出或處理錯誤的壞習慣

  

  好習慣:每個模塊都處理自己的錯誤



最終目的是希望人們能夠使用您的類,而不必瞭解其中的工作原理。如果他們使用的方法不正確或者不是按照期望的方法使用,也不需要猜測不能工作的原因。作爲一個好鄰居,您需要知道對您的類進行重用的人並沒有特異功能,因此您需要解決猜測的問題。

3.避免看到美杜莎

   在我最初瞭解 OO 概念時,我十分懷疑接口是否真正有幫助。我的同事給我打了個比方,說不使用接口就好像看到美杜莎的頭。在希臘神話中,美杜莎是長着蛇發的女怪。凡是看了她 一眼的人都會變成石頭。殺死美杜莎的珀爾休斯通過在盾上觀察她的影子,避免了變成石頭而得以與她對抗。

   接口就是對付美杜莎的鏡子。當您使用一個特定的具體實現時,代碼也必須隨着實現代碼的更改而更改。直接使用實現將限制您的選擇,因爲您已經在本質上把類變成了 “石頭”。

   壞習慣:不使用接口

 清單 6 顯示了從數據庫中裝入 Person 對象的示例。它將獲取人員的姓名並返回數據庫中匹配的 Person 對象。


  清單 6. 不使用接口的壞習慣

 

在環境發生更改之前,從數據庫中裝入 Person 的代碼都可以正常運行。例如,從數據庫裝入 Person 可能適用於第一個版本的應用程序,但是對於第二個版本,可能需要添加從 Web 服務裝入人員的功能。其實,該類已經變成 “石頭”,因爲它在直接使用實現類並且現在能做的更改十分有限

 好習慣:使用接口

  清單 7 顯示了一個代碼示例,在實現了加載用戶的新方法後並沒有進行更改。該示例顯示了一個名爲 PersonProvider 的接口,該接口將聲明單個方法。如果任何代碼使用 PersonProvider,代碼都禁止直接使用實現類。相反,它就像是一個實際對象一樣使用 PersonProvider

 清單 7. 使用接口的好習慣

 

   在使用接口時,嘗試避免直接引用實現類。相反,使用對象外部的內容可以提供正確的實現。如果您的類將裝入基於某些邏輯的實現,它仍然需要獲取所有實現類的定義,並且那樣做也無法取得任何效果。

您可以使用 Factory 模式來創建實現接口的實現類的實例。根據約定,factory 方法將以 create 爲開頭並返回接口。它可以爲您的 factory 獲取必要的參數以計算出應當返回哪個實現類。

在清單 7 中,createProvider() 方法只是獲取 $type。如果 $type 被設爲 database,工廠將返回 DBPersonProvider 的實例。從數據庫中裝入人員的任何新實現都不要求在使用工廠和接口的類中進行任何更改。DBPersonProvider 將實現 PersonProvider 接口並且擁有 getPerson() 方法的實際實現。

4.利用最弱的鏈接

   將模塊鬆散耦合 在一起是件好事情;它是允許您封裝更改的屬性之一。另外兩個習慣 — “保持謹慎” 和 “避免看到美杜莎” — 可幫助您構建鬆散耦合的模塊。要實現鬆散耦合的類,可通過養成降低類依賴關係的習慣實現。

   壞習慣:緊密耦合

在清單 8 中,降低依賴關係並不是必須降低使用對象的客戶機的依賴關係。相反,該示例將演示如何降低與正確類的依賴關係並最小化這種依賴關係。

  清單 8. Address 中緊密耦合的壞習慣



Address 對象上調用 format() 方法的代碼可能看上去很棒 — 這段代碼所做的是使用 Address 類,調用 format() 並完成。相反,Address 類就沒那麼幸運。它需要了解用於正確格式化的各種格式化方法,這可能使 Address 對象無法被其他人很好地重用,尤其是在其他人沒有興趣在 format() 方法中使用格式化方法類的情況下。雖然使用 Address 的代碼沒有許多依賴關係,但是 Address 類卻有大量代碼,而它可能只是一個簡單的數據對象。

Address 類與知道如何格式化 Address 對象的實現類緊密耦合。

   好習慣:在對象之間鬆散耦合

   在構建優秀的 OO 設計時,必須考慮稱爲關注點分離(Separation of Concerns,SoC)的概念。SoC 指嘗試通過真正關注的內容分離對象,從而降低耦合度。在最初的 Address 類中,它必須關注如何進行格式化。這可能不是優秀的設計。然而,Address 類應當考慮 Address 的各部分,而某種格式化方法應當關注如何正確格式化地址。

在清單 9 中,格式化地址的代碼被移到接口、實現類和工廠中 — 養成 “使用接口” 的習慣。現在,AddressFormatUtils 類負責創建格式化方法並格式化 Address。任何其他對象現在都可以使用 Address 而不必擔心要求獲得格式化方法的定義。

   清單 9. 在對象之間鬆散耦合的好習慣

 

當然,缺點是隻要使用模式,通常就意味着工件(類、文件)的數量會增加。但是,通過減少每個類中的維護可以彌補這個缺點,甚至在獲得正確的可重用性時反而可以減少工件量。

5.您是橡皮;我是膠水

   具有高度內聚力的 OO 設計被集中並組織到相關模塊中。瞭解 “關注點” 對於決定如何緊密地聯繫函數和類十分重要。

   壞習慣:降低內聚力

   當設計的內聚力較低 時,它就不能良好地組織類和方法。意大利麪條式代碼(spaghetti code)一詞通常用於描述捆綁在一起並且具有低內聚力的類和方法。清單 10 提供了意大利麪條式代碼的示例。相對通用的 Utils 類將使用許多不同對象並且有許多依賴關係。它執行很多操作,因而很難實現重用。

   清單 10. 降低內聚力的壞習慣


   好習慣:利用高內聚力

高內聚力 指將相互關聯的類和方法分組在一起。如果方法和類都具有高度的內聚力,則可以輕鬆地分解整個組而不影響設計。具有高內聚力的設計將提供降低耦合的機會。清單 11 顯示了被較好組織到類中的兩個方法。AddressUtils 類將包含用於處理 Address 類的方法,顯示了與地址相關的方法之間的高度內聚力。同樣地,PersonUtils 將包含專門處理 Person 對象的方法。這兩個擁有高度內聚力方法的新類的耦合性都很低,因爲可以完全獨立地使用。

清單 11. 高內聚力的好習慣



6.限制傳播

  OO 語言最大的敵人是複製和粘貼操作。當在缺少預先 OO 設計的情況下使用時,沒有任何操作會像在類之間複製代碼那樣具有破壞性。無論何時,如果想將代碼從一個類複製到下一個類中,請停下來並考慮如何使用類層次 結構利用類似功能或相同功能。在大多數情況下,使用優秀設計後,您將會發現完全沒有必要複製代碼。

  壞習慣:不使用類層次結構

  清單 12 顯示了部分類的簡單示例。它們從重複的字段和方法開始 — 從長遠來看,不利於應用程序作出更改。如果 Person 類中有缺陷,則 Employee 類中也很可能有一個缺陷,因爲看上去似乎實現是在兩個類之間複製的。

 清單 12. 不使用層次結構的壞習慣

 

繼承 是一個很難入手的習慣,因爲構建正確繼承模型的分析通常需要花費大量時間。反過來,使用 Ctrl+C 組合鍵和 Ctrl+V 組合鍵構建新實現只需幾秒鐘。但是省下的這部分時間通常會在維護階段迅速抵銷掉,因爲應用程序實際上將花費大量進行維護。

好習慣:利用繼承

在清單 13 中,新 Employee 類將擴展 Person 類。它現在將繼承所有通用方法並且不重新實現這些方法。此外,清單 13 顯示了抽象方法的用法,演示如何將基本功能放入基類中以及如何阻止實現類使用特定函數。

清單 13. 利用繼承的好習慣

7.考慮使用模式

設計模式指對象和方法的常見交互,並且時間證明它可以解決某些問題。當您考慮使用設計模式時,您就需要了解類之間如何進行交互。它是構建類及其交互操作的簡單方法,無需重蹈他人的覆轍,並從經過證明的設計中獲益。

壞習慣:一次考慮一個對象

實際上沒有適當的代碼示例可以演示如何考慮使用模式(儘管有豐富的優秀示例可以顯示模式實現)。但是,一般而言,您知道在滿足以下條件時一次只能考慮一個對象:

  • 不會提前設計對象模型。
  • 開始編寫單一方法的實現,而無需去掉大部分模型。
  • 在交談中不使用設計模式名而寧願談論實現。

好習慣:同時添加模式中形成的對象

一般而言,當您在執行以下操作時就是在考慮使用模式:

  • 提前構建類及其交互操作。
  • 根據模式套用類。
  • 使用模式名,如 Factory、SingletonFacade
  • 去掉大部分模型,然後開始添加實現。

 

 

 

原文出處:http://www.ibm.com/developerworks/cn/opensource/os-php-7oohabits/index.html


發佈了29 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章