2010-08-07 62 views
4

讓我們想象一下,我們有登記的圖案......註冊模式和註冊的對象的延遲實例

<?php 

class Registry 
{ 

private static $objects  = array(); 
private static $instance = null; 

public static function getInstance() { 
    if (self::$instance == null) { 
     self::$instance = new Registry(); 
    } 
    return self::$instance; 
} 

protected function _get($key) { 
    return ($this->objects[$key]) ? $this->objects[$key] : null; 
} 

protected function _set($key, $val) { 
    $this->objects[$key] = $val; 
} 

public static function get($key) { 
    return self::getInstance()->_get($key); 
} 

public static function set($key, $object) { 
    return self::getInstance()->_set($key, $object); 
} 

} 
?> 

使用這種認識是很容易的......

<? 
Registry::set('db', $db_client); 
Registry::set('redis', $redis_client); 

//Using registered objects is really easy 
Registry::get('db')->query("..."); 
Registry::get('redis')->get("..."); 
?> 

但正如你所看到的,即使我們不需要它們,我們也會將實例添加到註冊表中(是的,這關乎性能)。 所以,問題是...如何修改註冊表模式,以便能夠做懶惰的實例化?

以下是我在找...

<? 
class Registry 
{ 

private static $objects  = array(); 
private static $instance = null; 

public static function getInstance() { 
    if (self::$instance == null) { 
     self::$instance = new Registry(); 
    } 
    return self::$instance; 
} 

protected function _db() { 
    if (!$this->objects['db']) { 
     $this->objects['db'] = new DatabaseAdapter(DB_HOST, DB_NAME, DB_USER, DB_PASSWORD); 
    } 
    return $this->objects['db']; 
} 

protected function _redis() { 
    if (!$this->objects['redis']) { 
     $this->objects['redis'] = new Redis(REDIS_HOST, REDIS_DB, REDIS_USER, REDIS_PASSWORD); 
    } 
    return $this->objects['redis']; 
} 

public static function db() { 
    return self::getInstance()->_db(); 
} 

public static function redis() { 
    return self::getInstance()->_redis(); 
} 

} 
?> 

正如你所看到的,DatabaseAdapter()Redis()將創建只有在我們將要求他們。一切似乎都沒問題,但正如你可以看到它不是一個獨立的類,因爲_db(),_redis()方法包含連接常量等。 如何避免它?我如何在註冊表類中定義註冊表方法以將Registy類和其內部的對象分開?

我真的很抱歉我的英語,但我希望你很清楚。

謝謝。

PS:上面的所有代碼都寫了1分鐘。之前並沒有經過測試。

回答

4

如果您使用全局常量,將始終依賴於全局範圍。它並不重要。另外,即使你不使用常量,你仍然對Registry中的Database類有依賴關係。如果你想解散那些依賴,也可以使用上要創建類工廠方法:

public function get($service) 
{ 
    if(!this->_data[$service]) { 
     // requires PHP 5.2.3 
     this->_data[$service] = call_user_func($service .'::create'); 
    } 
    return this->_data[$service]; 
} 

所以,如果你get('DB'),代碼會嘗試打電話給你要創建的類中的靜態DB::create()方法。但正如我所說,如果您使用全局常量進行配置,則只需將問題移到另一個類中即可。

db類可以是這樣的:

class DB 
{ 
    protected static $_config; 
    public static setConfig(array $config) 
    { 
     self::_config = $config; 
    } 
    public static create() 
    { 
     return new self(
      self::config['host'], 
      self::config['db'], 
      self::config['user'], 
      self::config['pass']); 
    } 
} 

的配置可以存儲在外部配置文件,您引導過程中加載並設置爲DB類中,如

DB::setConfig(parse_ini_file('/path/to/db-config.ini')); 

這樣做的缺點是,你必須添加所有的地方create()方法和所有類都必須能夠存儲自己的配置。您可以將這些責任集中到一個Builder pattern。但是,如果你這樣做,你是半路上反正實施一個IoC Container,所以請查看以下資源:

+0

在5.3,你可以這樣做:返回本 - > _數據[$服務]: - ($服務 '::創建')返回此> _數據[$服務] = call_user_func – 2013-06-14 00:47:44

+0

@ChrisDaMour但爲什麼我會在可讀性較差的時候? – Gordon 2013-06-14 04:53:07

+0

這只是一個意見,我發現它比if塊更清潔 – 2013-06-14 06:39:29

0

注意:您正在使用$對象的「靜態」修飾符 - 當您使用實例時,這是probaby沒有必要的。

如何在註冊表類中定義註冊表方法以將Registy類和其內部的對象分開?

它們總是分開的:註冊表類中的每個對象只是對(獨立)對象的引用。但是,如果這個問題是關於包含適當的類定義(?),那麼可以使用class_exists()函數根據需要儘快加載類。

BurninLeo