扩展抽象单例类

发布于 2024-08-13 07:26:10 字数 771 浏览 3 评论 0原文

如果您有一个创建某种新对象的工厂类,并且该工厂类是一个单例,如下所示:

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

你会做什么?

If you had a factory class that creates new objects of some kind, and that factroy class is a singleton, like this:

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;
    }
}

The same code repeats anytime where some object needs it's own factory. So i decided to make this factory class abstract and implement only specific routines for each factory. But PHP does not allow to instantiate abstract class.

abstract class Base_Factory {
    public static function getInstance(){
        if (!self::$factory)
            self::$factory = new self();
        return self::$factory;
    }
}

Fatal error: Cannot instantiate abstract class Base_Factory

What would you do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

你的往事 2024-08-20 07:26:10

在 PHP 方法中,self 始终引用定义该方法的类。从 5.3.0 版本开始,PHP 支持“后期静态绑定”,您可以使用 static 关键字来访问重写的静态方法,以及函数 get_ Called_class()获取静态上下文中派生类的名称。

但是,您的设计有一个重大缺陷:Base_Factory 中定义的静态属性 $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];
    }
}

哦,还有一件事:您正在寻找重用单例对象代码的可能性这一事实可能表明您过度使用了单例设计模式!问问自己,您计划作为单例实现的类是否真的是单例,以及是否不存在您可能希望拥有特定类的多个实例的用例。

通常,最好只使用一个代表当前“应用程序上下文”的单例,该单例为相对于该上下文为单例的对象提供访问器。

In PHP methods, self always refers to the class where the method is defined. Since version 5.3.0, PHP supports “late static binding”, where you can use the static keyword to access overridden static methods, as well as the function get_called_class() to get the name of the derived class in static context.

However, your design has a major flaw: The static property $factory defined in Base_Factory is shared across all derived classes. Therefore, the first time a singleton is created and stored in this property, all other calls to getInstance() will return the same object, no matter what derived class is used.

You could use a static dictionary mapping class names to singleton objects:

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];
    }
}

Oh, one more thing: The fact that you are looking for a possibility to re-use code for singleton objects could be a cue to the fact that you are over-using the singleton design pattern! Ask yourself if the classes you are planning to implement as singletons really are singletons and if there will be no use case where you might want to have multiple instances of the particular class.

Often it is much better to use just one singleton representing the current “application context” that provides accessors for objects that are singletons with respect to this context.

十雾 2024-08-20 07:26:10

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;
    }
}

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;
    }
}
命硬 2024-08-20 07:26:10

仅 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;
    }
}

PHP >= 5.3 only

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;
    }
}
闻呓 2024-08-20 07:26:10

在像这样的简单类中注册您的单例

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

Register your singletons in a simple class like this

class Singletons {
    static private $singleton = array();
    public function getSingleton($class) {
    if (!isset(self::$singleton[$class])) {
        self::$singleton[$class] = new $class;
    }
    return self::$singleton[$class];
    }
}

Then do this

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();

Output

aSingleton called 1 times
aSingleton called 2 times
↙厌世 2024-08-20 07:26:10

根据定义,抽象类不能像任何其他面向对象语言一样在 PHP 中实例化。所以你的 Base_Factory 应该是接口而不是抽象类。

PHP 手册中:“不允许创建已定义为抽象的类的实例。”

By definition abstract classess cannot be instantiated in PHP like any other object oriented languages. So your Base_Factory should be interface instead of abstract class.

From the PHP manual: "It is not allowed to create an instance of a class that has been defined as abstract."

带上头具痛哭 2024-08-20 07:26:10

那么您可以进行检查以确保调用该函数的类不是 Base_Factory。

if(__CLASS__!='Base_Factory')

然后使用 $this 而不是 self 来引用当前对象而不是当前类。

if (!$this->factory)
        $this->factory = new self();
    return $this->factory;

Well you could do a check to make sure the class calling the function isn't the Base_Factory.

if(__CLASS__!='Base_Factory')

Then use $this instead of self to refer to the current object instead of the current class.

if (!$this->factory)
        $this->factory = new self();
    return $this->factory;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文