工廠模式
在大型系統中,許多代碼依賴于少數幾個關鍵類。需要更改這些類時,可能會出現困難。例如,假設您有一個從文件讀取的?User
?類。您希望將其更改為從數據庫讀取的其他類,但是,所有的代碼都引用從文件讀取的原始類。這時候,使用工廠模式會很方便。
工廠模式?是一種類,它具有為您創建對象的某些方法。您可以使用工廠類創建對象,而不直接使用?new
。這樣,如果您想要更改所創建的對象類型,只需更改該工廠即可。使用該工廠的所有代碼會自動更改。
清單 1 顯示工廠類的一個示列。等式的服務器端包括兩個部分:數據庫和一組 PHP 頁面,這些頁面允許您添加反饋、請求反饋列表并獲取與特定反饋相關的文章。
清單 1. Factory1.php
<?php
interface IUser
{function getName();
}class User implements IUser
{public function __construct( $id ) { }public function getName(){return "Jack";}
}class UserFactory
{public static function Create( $id ){return new User( $id );}
}$uo = UserFactory::Create( 1 );
echo( $uo->getName()."\n" );
?>
單元素模式(單列模式)
某些應用程序資源是獨占的,因為有且只有一個此類型的資源。例如,通過數據庫句柄到數據庫的連接是獨占的。您希望在應用程序中共享數據庫句柄,因為在保持連接打開或關閉時,它是一種開銷,在獲取單個頁面的過程中更是如此。
單元素模式可以滿足此要求。如果應用程序每次包含且僅包含一個對象,那么這個對象就是一個單元素(Singleton)。清單 3 中的代碼顯示了 PHP V5 中的一個數據庫連接單元素。
- php的應用主要在于數據庫應用, 一個應用中會存在大量的數據庫操作, 在使用面向對象的方式開發時, 如果使用單例模式, 則可以避免大量的new 操作消耗的資源,還可以減少數據庫連接這樣就不容易出現 too many connections情況。
- 如果系統中需要有一個類來全局控制某些配置信息, 那么使用單例模式可以很方便的實現. 這個可以參看zend Framework的FrontController部分。
- 在一次頁面請求中,?便于進行調
清單 3. Singleton.php
<?php
require_once("DB.php");class DatabaseConnection
{public static function get(){static $db = null;if ( $db == null )$db = new DatabaseConnection();return $db;}private $_handle = null;private function __construct(){$dsn = 'mysql://root:password@localhost/photos';$this->_handle =& DB::Connect( $dsn, array() );}public function handle(){return $this->_handle;}
}print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
print( "Handle = ".DatabaseConnection::get()->handle()."\n" );
?>
您可以使用全局變量存儲數據庫句柄,但是,該方法僅適用于較小的應用程序。在較大的應用程序中,應避免使用全局變量,并使用對象和方法訪問資源。
觀察者模式
觀察者模式為您提供了避免組件之間緊密耦合的另一種方法。該模式非常簡單:一個對象通過添加一個方法(該方法允許另一個對象,即觀察者?注冊自己)使本身變得可觀察。當可觀察的對象更改時,它會將消息發送到已注冊的觀察者。這些觀察者使用該信息執行的操作與可觀察的對象無關。結果是對象可以相互對話,而不必了解原因。
一個簡單示例是系統中的用戶列表。清單 4 中的代碼顯示一個用戶列表,添加用戶時,它將發送出一條消息。添加用戶時,通過發送消息的日志觀察者可以觀察此列表。
清單 4. Observer.php
<?php
interface IObserver
{function onChanged( $sender, $args );
}interface IObservable
{function addObserver( $observer );
}class UserList implements IObservable
{private $_observers = array();public function addCustomer( $name ){foreach( $this->_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->add
此代碼定義四個元素:兩個接口和兩個類。IObservable
?接口定義可以被觀察的對象,UserList
?實現該接口,以便將本身注冊為可觀察。IObserver
?列表定義要通過怎樣的方法才能成為觀察者,UserListLogger
?實現?IObserver
?接口。圖 4 的 UML 中展示了這些元素。
圖 4. 可觀察的用戶列表和用戶列表事件日志程序
如果在命令行中運行它,您將看到以下輸出:
% php observer.php 'Jack' added to user list %
測試代碼創建?UserList
,并將?UserListLogger
?觀察者添加到其中。然后添加一個消費者,并將這一更改通知?UserListLogger
。
認識到?UserList
?不知道日志程序將執行什么操作很關鍵。可能存在一個或多個執行其他操作的偵聽程序。例如,您可能有一個向新用戶發送消息的觀察者,歡迎新用戶使用該系統。這種方法的價值在于?UserList
?忽略所有依賴它的對象,它主要關注在列表更改時維護用戶列表并發送消息這一工作。
此模式不限于內存中的對象。它是在較大的應用程序中使用的數據庫驅動的消息查詢系統的基礎。
?
策略模式
我們講述的最后一個設計模式是策略?模式。在此模式中,算法是從復雜類提取的,因而可以方便地替換。例如,如果要更改搜索引擎中排列頁的方法,則策略模式是一個不錯的選擇。思考一下搜索引擎的幾個部分 —— 一部分遍歷頁面,一部分對每頁排列,另一部分基于排列的結果排序。在復雜的示例中,這些部分都在同一個類中。通過使用策略模式,您可將排列部分放入另一個類中,以便更改頁排列的方式,而不影響搜索引擎的其余代碼。