理解PHP的原廠模式Factory Pattern

來源:互聯網
上載者:User
工廠類就是一個專門用來建立其它對象的類,工廠類在多態性編程實踐中是非常重要的。它允許動態替換類,修改配置,會使應用程式更加靈活。掌握原廠模式對Web開發是必不可少的。

原廠模式通常用來返回類似介面的不同的類,工廠的一種常見用法就是建立多態的提供者。

通常原廠模式有一個關鍵的構造,即一般被命名為factory的靜態方法。這個靜態方法可以接受任意數量的參數,並且必須返回一個對象。

Program List:基本的工廠類

<?php
class Fruit {
// 對象從工廠類返回
}

Class FruitFactory {

public static function factory() {
// 返回對象的一個新執行個體
return new Fruit();
}
}

// 調用工廠
$instance = FruitFactory::factory();
?>

Program List:利用工廠類生產對象

<?php
class Example
{
// The parameterized factory method
public static function factory($type)
{
if (include_once 'Drivers/' . $type . '.php') {
$classname = 'Driver_' . $type;
return new $classname;
} else {
throw new Exception('Driver not found');
}
}
}
// Load a MySQL Driver
$mysql = Example::factory('MySQL');
// Load an SQLite Driver
$sqlite = Example::factory('SQLite');
?>

Program List:一個完整的工廠類

下面的程式定義了一個通用的工廠類,它生產能夠儲存你所有操作的Null 物件,你可以獲得一個執行個體,這些操作都在那個執行個體中了。

<?php

/**
* Generic Factory class
*
* This Magic Factory will remember all operations you perform on it,
* and apply them to the object it instantiates.
*
*/
class FruitFactory {
private $history, $class, $constructor_args;

/**
* Create a factory of given class. Accepts extra arguments to be passed to
* class constructor.
*/
function __construct( $class ) {
$args = func_get_args();
$this->class = $class;
$this->constructor_args = array_slice( $args, 1 );
}

function __call( $method, $args ) {
$this->history[] = array(
'action' => 'call',
'method' => $method,
'args' => $args
);
}

function __set( $property, $value ) {
$this->history[] = array(
'action' => 'set',
'property' => $property,
'value' => $value
);
}

/**
* Creates an instance and performs all operations that were done on this MagicFactory
*/
function instance() {
# use Reflection to create a new instance, using the $args
$reflection_object = new ReflectionClass( $this->class );
$object = $reflection_object->newInstanceArgs( $this->constructor_args );

# Alternative method that doesn't use ReflectionClass, but doesn't support variable
# number of constructor parameters.
//$object = new $this->class();

# Repeat all remembered operations, apply to new object.
foreach( $this->history as $item ) {
if( $item['action'] == 'call' ) {
call_user_func_array( array( $object, $item['method'] ), $item['args'] );
}
if( $item['action'] == 'set' ) {
$object->{$item['property']} = $item['value'];
}
}

# Done
return $object;
}
}

class Fruit {
private $name, $color;
public $price;

function __construct( $name, $color ) {
$this->name = $name;
$this->color = $color;
}

function setName( $name ) {
$this->name = $name;
}

function introduce() {
print "Hello, this is an {$this->name} {$this->sirname}, its price is {$this->price} RMB.";
}
}

# Setup a factory
$fruit_factory = new FruitFactory('Fruit', 'Apple', 'Gonn');
$fruit_factory->setName('Apple');
$fruit_factory->price = 2;

# Get an instance
$apple = $fruit_factory->instance();
$apple->introduce();
?>

程式運行結果:

Hello, this is an Apple , its price is 2 RMB.

原廠模式主要是為建立對象提供過渡介面,以便將建立對象的具體過程屏蔽隔離起來,達到提高靈活性的目的。

原廠模式可以分為三類:

簡單原廠模式(Simple Factory)

Factory 方法模式(Factory Method)

抽象原廠模式(Abstract Factory)

這三種模式從上到下逐步抽象,並且更具一般性。

簡單原廠模式又稱靜態Factory 方法模式。重新命名上就可以看出這個模式一定很簡單。它存在的目的很簡單:定義一個用於建立對象的介面。Factory 方法模式去掉了簡單原廠模式中Factory 方法的靜態屬性,使得它可以被子類繼承。這樣在簡單原廠模式裡集中在Factory 方法上的壓力可以由Factory 方法模式裡不同的工廠子類來分擔。

Factory 方法模式彷彿已經很完美的對對象的建立進行了封裝,使得客戶程式中僅僅處理抽象產品角色提供的介面。那我們是否一定要在代碼中遍布工廠呢?大可不必。也許在下面情況下你可以考慮使用Factory 方法模式:

當客戶程式不需要知道要使用對象的建立過程。

客戶程式使用的對象存在變動的可能,或者根本就不知道使用哪一個具體的對象。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.