1. 程式人生 > >php演算法和資料結構

php演算法和資料結構

php五種設計模式

設計模式 一書將設計模式引入軟體社群,該書的作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗稱 “四人幫”)。所介紹的設計模式背後的核心概念非常簡單。經過多年的軟體開發實踐,Gamma 等人發現了某些具有固定設計的模式,就像建築師設計房子和建築物一樣,可以為浴室的位置或廚房的構造方式開發模板。使用這些模板或者說設計模式 意味著可以更快地設計更好的建築物。同樣的概念也適用於軟體。 設計模式不僅代表著更快開發健壯軟體的有用方法,而且還提供了以友好的術語封裝大型理念的方法。例如,您可以說您正在編寫一個提供鬆散耦合的訊息傳遞系統,也可以說你正在編寫名稱為觀察者 的模式。 用較小的示例展示模式的價值是非常困難的。這往往有些大材小用的意味,因為模式實際上是在大型程式碼庫中發揮作用的。本文不展示大型應用程式,所以您需要思索的是在您自己的大型應用程式中應用示例原理的方法 —— 而不是本文演示的程式碼本身。這不是說您不應該在小應用程式中使用模式。很多良好的應用程式都以小應用程式為起點,逐漸發展到大型應用程式,所以沒有理由不以此類紮實的編碼實踐為基礎。 既然您已經瞭解了設計模式以及它們的有用之處,現在我們來看看 PHP V5 的五種常用模式。 工廠模式 最初在設計模式 一書中,許多設計模式都鼓勵使用鬆散耦合。要理解這個概念,讓我們最好談一下許多開發人員從事大型系統的艱苦歷程。在更改一個程式碼片段時,就會發生問題,系統其他部分 —— 您曾認為完全不相關的部分中也有可能出現級聯破壞。 該問題在於緊密耦合 。系統某個部分中的函式和類嚴重依賴於系統的其他部分中函式和類的行為和結構。您需要一組模式,使這些類能夠相互通訊,但不希望將它們緊密繫結在一起,以避免出現聯鎖。 在大型系統中,許多程式碼依賴於少數幾個關鍵類。需要更改這些類時,可能會出現困難。例如,假設您有一個從檔案讀取的 User 類。您希望將其更改為從資料庫讀取的其他類,但是,所有的程式碼都引用從檔案讀取的原始類。這時候,使用工廠模式會很方便。 工廠模式 是一種類,它具有為您建立物件的某些方法。您可以使用工廠類建立物件,而不直接使用 new。這樣,如果您想要更改所建立的物件型別,只需更改該工廠即可。使用該工廠的所有程式碼會自動更改。 清單 1 顯示工廠類的一個示列。等式的伺服器端包括兩個部分:資料庫和一組 PHP 頁面,這些頁面允許您新增反饋、請求反饋列表並獲取與特定反饋相關的文章。 清單 1. Factory1.php getName().”\n” ); ?> IUser 介面定義使用者物件應執行什麼操作。IUser 的實現稱為 User,UserFactory 工廠類則建立 IUser 物件。此關係可以用圖 1 中的 UML 表示。 工廠類及其相關 IUser 介面和使用者類 如果您使用 php 直譯器在命令列上執行此程式碼,將得到如下結果: % php factory1.php Jack % 測試程式碼會向工廠請求 User 物件,並輸出 getName 方法的結果。 有一種工廠模式的變體使用工廠方法。類中的這些公共靜態方法構造該型別的物件。如果建立此型別的物件非常重要,此方法非常有用。例如,假設您需要先建立物件,然後設定許多屬性。此版本的工廠模式會將該程序封裝在單個位置中,這樣,不用複製複雜的初始化程式碼,也不必將複製好的程式碼在在程式碼庫中到處貼上。 清單 2 顯示使用工廠方法的一個示例。 清單 2. Factory2.php getName().”\n” ); ?> 這段程式碼要簡單得多。它僅有一個介面 IUser 和一個實現此介面的 User 類。User 類有兩個建立物件的靜態方法。此關係可用圖 2 中的 UML 表示。 IUser 介面和帶有工廠方法的使用者類 在命令列中執行指令碼產生的結果與清單 1 的結果相同,如下所示: % php factory2.php Jack % 如上所述,有時此類模式在規模較小的環境中似乎有些大材小用。不過,最好還是學習這種紮實的編碼形式,以便應用於任意規模的專案中。 單元素模式 某些應用程式資源是獨佔的,因為有且只有一個此型別的資源。例如,通過資料庫控制代碼到資料庫的連線是獨佔的。您希望在應用程式中共享資料庫控制代碼,因為在保持連線開啟或關閉時,它是一種開銷,在獲取單個頁面的過程中更是如此。 單元素模式可以滿足此要求。如果應用程式每次包含且僅包含一個物件,那麼這個物件就是一個單元素(Singleton)。清單 3 中的程式碼顯示了 PHP V5 中的一個數據庫連線單元素。 清單 3. Singleton.php _handle =& DB::Connect( $dsn, array() ); } public function handle() { return $this->_handle; } } print( “Handle = “.DatabaseConnection::get()->handle().”\n” ); print( “Handle = “.DatabaseConnection::get()->handle().”\n” ); ?> 此程式碼顯示名為 DatabaseConnection 的單個類。您不能建立自已的 DatabaseConnection,因為建構函式是專用的。但使用靜態 get 方法,您可以獲得且僅獲得一個 DatabaseConnection 物件。此程式碼的 UML 如圖 3 所示。 在兩次呼叫間,handle 方法返回的資料庫控制代碼是相同的,這就是最好的證明。您可以在命令列中執行程式碼來觀察這一點。 % php singleton.php Handle = Object id #3 Handle = Object id #3 % 返回的兩個控制代碼是同一物件。如果您在整個應用程式中使用資料庫連線單元素,那麼就可以在任何地方重用同一控制代碼。 您可以使用全域性變數儲存資料庫控制代碼,但是,該方法僅適用於較小的應用程式。在較大的應用程式中,應避免使用全域性變數,並使用物件和方法訪問資源。 觀察者模式 觀察者模式為您提供了避免元件之間緊密耦合的另一種方法。該模式非常簡單:一個物件通過新增一個方法(該方法允許另一個物件,即觀察者 註冊自己)使本身變得可觀察。當可觀察的物件更改時,它會將訊息傳送到已註冊的觀察者。這些觀察者使用該資訊執行的操作與可觀察的物件無關。結果是物件可以相互對話,而不必瞭解原因。 一個簡單示例是系統中的使用者列表。清單 4 中的程式碼顯示一個使用者列表,新增使用者時,它將傳送出一條訊息。新增使用者時,通過傳送訊息的日誌觀察者可以觀察此列表。 清單 4. Observer.php _observers as $obs ) $obs->onChanged( $this, $name ); } public function addObserver( $observer ) { $this->_observers []= $observer; } } class UserListLogger implements IObserver { public function onChanged( $sender, $args ) { echo( “‘$args’ added to user list\n” ); } } $ul = new UserList(); $ul->addObserver( new UserListLogger() ); $ul->addCustomer( “Jack” ); ?> 此程式碼定義四個元素:兩個介面和兩個類。IObservable 介面定義可以被觀察的物件,UserList 實現該介面,以便將本身註冊為可觀察。IObserver 列表定義要通過怎樣的方法才能成為觀察者,UserListLogger 實現 IObserver 介面。圖 4 的 UML 中展示了這些元素。 圖 4. 可觀察的使用者列表和使用者列表事件日誌程式 可觀察的使用者列表和使用者列表事件日誌程式 如果在命令列中執行它,您將看到以下輸出: % php observer.php ‘Jack’ added to user list % 測試程式碼建立 UserList,並將 UserListLogger 觀察者新增到其中。然後新增一個消費者,並將這一更改通知 UserListLogger。 認識到 UserList 不知道日誌程式將執行什麼操作很關鍵。可能存在一個或多個執行其他操作的偵聽程式。例如,您可能有一個向新使用者傳送訊息的觀察者,歡迎新使用者使用該系統。這種方法的價值在於 UserList 忽略所有依賴它的物件,它主要關注在列表更改時維護使用者列表併發送訊息這一工作。 此模式不限於記憶體中的物件。它是在較大的應用程式中使用的資料庫驅動的訊息查詢系統的基礎。 命令鏈模式 命令鏈 模式以鬆散耦合主題為基礎,傳送訊息、命令和請求,或通過一組處理程式傳送任意內容。每個處理程式都會自行判斷自己能否處理請求。如果可以,該請求被處理,程序停止。您可以為系統新增或移除處理程式,而不影響其他處理程式。清單 5 顯示了此模式的一個示例。 清單 5. Chain.php _commands []= $cmd; } public function runCommand( $