在面向對象編程中, 最通常的方法是一個new操作符產生一個對象實例,new操作符就是用來構造對象 實例的。但是在一些情況下, new操作符直接生成對象會帶來一些問題。舉例來說, 許多類型對象的創造 需要一系列的步驟: 你可能需要計算或取得對象的初始設置; 選擇生成哪個子對象實例; 或在生成你需 要的對象之前必須先生成一些輔助功能的對象。 在這些情況, 新對象的建立就是一個 “過程 ”,不僅是一個操作,像一部大機器中的一個齒輪傳動。
問題
你如何能輕松方便地 建立這麼" 復雜 " 的對象即操作中不需要粘貼復制呢?
解決方法
建立一個工 廠(一個函數或一個類方法)來制造新的對象。為了理解工廠的用處, 試想以下的不同之處 ……
代碼:
$connection =& new MySQLConnection($user, $password, $database);
……使你的代碼可擴展和更簡潔 ……
$connection =& create_connection();
後者的代碼片斷集中在和 數據庫連接的create_connect()工廠上 ,就像剛才說的一樣,使創造數據庫連接的過程成為一個簡單的 操作—就像new操作一樣。工廠模式的優點就在創建對象上。 它的任務就是把對象的創建過程都封 裝起來,然後返回一個所需要的新類。
想改變對象的結構和建立對象的方式嗎? 你只需選擇對象 工廠,對代碼的改變只需要一次就夠了。( 工廠模式的功能是如此強大, 它處於是應用的底層, 所以在 許多其余的復雜模式和應用中它會不停地出現。)
樣本代碼
工廠模式封裝了對象的建立過 程。 你可以在對象本身創建對象工廠或者是一個額外的工廠類——這要看你具體的應用。讓 我們看一個工廠對象的例子。
我們發現下面代碼中,數據庫連接的那部分屢次出現:
// PHP4
class Product {
function getList() { $db =& new MysqlConnection (DB_USER, DB_PW, DB_NAME);
//...
}
function getByName($name) { $db =& new MysqlConnection(DB_USER, DB_PW, DB_NAME);
//...
}
//...
}
為什麼這樣做不好? 數據庫連接的參數出現的地方太多了,當你把這些參數設成常量, 意味著你統一定義並對他們進行賦值,顯然這種做法不是很妥當:
你可以輕松地改變連接數據庫 的參數,但你不能增加或改變這些參數地順序,除非你把所有連接代碼都改了。
你不能輕松的實 例化一個新類去連接另一種數據庫,比如說PostgresqlConnection。
這樣很難單獨測試和證實連 接對象的狀態。
使用工廠設計模式,代碼將得到很大的改進:
class Product {
function getList() {
$db =& $this->_getConnection();
//...
}
function &_getConnection() {
return new MysqlConnection(DB_USER, DB_PW, DB_NAME);
}
}
先前的類中存在很多調用new MysqlConnection(DB_USER, DB_PW, DB_NAME)的方法,現在都被集中到的_getConnection()方法上。
下面是工廠的另一種變 化,你靜態地調用了一個工廠類:
class Product {
function getList() {
$db =& DbConnectionBroker::getConnection();
//...
}
}
class DbConnectionBroker {
function &getConnection() {
return new MySQLConnection (DB_USER, DB_PW, DB_NAME);
}
}
這裡 DbConnectionBroker::getConnection()產生的效果和前面的一樣 ,但這樣卻很有好處: 我們不必在每個 需要連接數據庫的類中加入調用new MysqlConnection(DB_USER , DB_PW, DB_NAME)的方法。
當 然另一種變化就是引用一個外部工廠對象的資源,和這個對象定義了數據庫連接的參 數:
class Product {
var $_db_maker;
function setDbFactory (&$connection_factory) {
$this->_db_maker =& $connection_factory;
}
function getList() {
$db =& $this->_db_maker->getConnection();
//...
}
}