2010-03-28 16 views
6

當PHP創建一個Singleton,我保證它無法通過執行以下操作來實例化:在PHP中創建單例時,我可以使用抽象類而不是私有__construct()嗎?

class Singleton { 

    private function __construct() {} 
    private function __clone() {} 

    public static function getInstance() {} 
} 

但是,我意識到,定義一個類爲「抽象」意味着它不能被實例化。那麼,有什麼不好做,而不是以下:

abstract class Singleton { 

    public static function getInstance() {} 
} 

第二個場景讓我寫更少的代碼這將是很好的。 (並不是說它實際上有很大的區別)。

+0

酷,不知道在PHP中的抽象,它與PHP5出臺,那些傢伙不要浪費時間了,一直在增加新的酷功能。感謝和+1發佈這樣一個有趣的問題。 – 2010-03-28 14:44:27

+1

@Marco PHP 5自7年前的2004年7月以來一直在運行。不是一個真正的新功能。 – stefgosselin 2011-07-04 22:10:02

回答

10

當PHP創建一個單身,聲明__construct__clone私人確保類不能從外部實例化:它仍然可以從它的聲明中實例化。

當聲明一個類爲abstract,時,它根本不可能實例化;;甚至不在其聲明中。

這意味着您的解決方案將無法正常工作:在第二種情況下,您的getInstance()方法將無法實例化該類 - 儘管它可以在第一種情況下執行此操作。

2

不,因爲那時你根本就不能實例化類(即使在靜態getInstance方法中也沒有)。 singleton示例中的私有構造函數只是確保只有來自同一個類的靜態getInstance方法才能訪問構造函數。

0

它可以工作,如果你的Singleton::getInstance()應該返回一個不同類的實例。

abstract class Singleton { 
    public static function getInstance() { 
    static $instance = null; 
    if (is_null($instance)) { 
     $instance = new StdClass; // a different class than 'abstract class Singleton' 
     $instance->x = time(); 
    } 
    return $instance; 
    } 
} 

$obj = Singleton::getInstance(); 

但是我會覺得很困惑。有點像濫用abstract將抽象工廠的複雜性與單身人士的束縛結合起來。

1

不,您不能在創建單例時使用抽象類而不是私有__construct()。但是,如果你的目的是要創建一個抽象辛格爾頓要從中擴展,你可以這樣做是這樣的:

abstract class Singleton 
{ 
    private static $_instances; 
    public static function getInstance() 
    { 
     $className = get_called_class(); // As of PHP 5.3 
     if(! isset(self::$_instances[$className])) { 
     self::$_instances[$className] = new $className(); 
     } 
     return self::$_instances[$className]; 
    } 
    protected function __construct() {} 
    final private function __clone() {} 
    final private function __wakeup() {} 
} 

然後,您可以從辛格爾頓擴展這樣的:

class Foo extends Singleton { 

    protected $_foo = 1; 
    public function setFoo($i) { $this->_foo = $i; } 
    public function getFoo() { return $this->_foo; } 
} 

class Bar extends Singleton { 

    protected $_foo = 1; 
    public function setFoo($i) { $this->_foo = $i; } 
    public function getFoo() { return $this->_foo; } 
} 

和操縱:

$foo1 = Foo::getInstance(); 
$foo1->setFoo(5); 

$foo2 = Foo::getInstance(); 
var_dump($foo2); 

$bar1 = Bar::getInstance(); 
var_dump($bar1); 

echo new ReflectionObject($foo2); 
echo new ReflectionObject($bar1); 

但是,請記住,單身人士非常難以進行單元測試,應儘可能避免。見我的答案在這裏的一些背景:

+0

我並沒有試圖創建一個抽象的單例類,但我確信有人會發現這個有用,所以謝謝。我意識到單身人士的問題,我更喜歡使用DI或靜態註冊表和工廠;這個問題是爲了滿足我的好奇心!但是,我清楚地應該先測試出我的想法,從其他評論中可以看出。 – 2010-03-28 14:34:49

+1

+1是一個完美可用的[不應該使用的]例子(http://c2.com/cgi/wiki?SingletonsAreEvil)。 – stefgosselin 2011-07-04 22:14:16

相關問題