如果你有一个工厂类来创建某种类型的新对象,那个factroy类就是一个单例,如下所示:
class Database_Factory extends Base_Factory {
private static $factory;
private $objects = array();
public function __get($profile) {
// check for object and return it if it's created before
}
public static function getInstance(){
if (!self::$factory)
self::$factory = new self();
return self::$factory;
}
}
当某个对象需要它自己的工厂时,相同的代码会重复。所以我决定将这个工厂类抽象化,并且只为每个工厂实现特定的例程。但PHP不允许实例化抽象类。
abstract class Base_Factory {
public static function getInstance(){
if (!self::$factory)
self::$factory = new self();
return self::$factory;
}
}
致命错误:无法实例化抽象类Base_Factory
你会做什么?
答案 0 :(得分:36)
在PHP方法中,self
始终引用定义方法的类。从5.3.0版本开始,PHP支持“后期静态绑定”,您可以使用static
关键字来访问重写的静态方法,以及使用函数get_called_class()
来获取派生类的名称。静态背景。
但是,您的设计存在一个主要缺陷:$factory
中定义的静态属性Base_Factory
在所有派生类中共享。因此,第一次创建单例并将其存储在此属性中时,对getInstance()
的所有其他调用将返回相同的对象,无论使用何种派生类。
您可以使用静态字典将类名映射到单例对象:
abstract class Base_Factory {
private static $_instances = array();
public static function getInstance() {
$class = get_called_class();
if (!isset(self::$_instances[$class])) {
self::$_instances[$class] = new $class();
}
return self::$_instances[$class];
}
}
哦,还有一件事:您正在寻找重新使用单例对象代码的可能性,这可能是您过度使用单例设计模式的一个事实!问问自己,你计划作为单身人士实施的课程是否真的是单身,如果没有用例,你可能想要拥有特定课程的多个实例。
通常情况下,只使用一个表示当前“应用程序上下文”的单例更好,它为与此上下文相关的单例对象提供访问器。
答案 1 :(得分:8)
PHP 5.3 +
abstract class Singleton
{
/**
* Instance
*
* @var Singleton
*/
protected static $_instance;
/**
* Constructor
*
* @return void
*/
protected function __construct() {}
/**
* Get instance
*
* @return Singleton
*/
public final static function getInstance() {
if (null === static::$_instance) {
static::$_instance = new static();
}
return static::$_instance;
}
}
答案 2 :(得分:4)
PHP> =仅限5.3
abstract class Base_Factory {
protected static $factory;
public static function getInstance(){
if (!self::$factory) {
$class = get_called_class();
self::$factory = new $class();
}
return self::$factory;
}
}
答案 3 :(得分:1)
在像这样的简单课程中注册您的单身人士
class Singletons {
static private $singleton = array();
public function getSingleton($class) {
if (!isset(self::$singleton[$class])) {
self::$singleton[$class] = new $class;
}
return self::$singleton[$class];
}
}
然后这样做
class aSingleton {
public $i;
public function test() {
++$this->i;
echo get_class() . " called {$this->i} times\n";
}
}
Singletons::getSingleton('aSingleton')->test();
Singletons::getSingleton('aSingleton')->test();
输出
aSingleton called 1 times
aSingleton called 2 times
答案 4 :(得分:-1)
根据定义,抽象classess不能像任何其他面向对象的语言一样在PHP中实例化。所以你的Base_Factory应该是接口而不是抽象类。
从PHP手册:“不允许创建已定义为抽象的类的实例。”
答案 5 :(得分:-2)
您可以检查以确保调用该函数的类不是Base_Factory。
if(__CLASS__!='Base_Factory')
然后使用$ this而不是self来引用当前对象而不是当前类。
if (!$this->factory)
$this->factory = new self();
return $this->factory;