具有 public 构造函数的单例模式

Singleton Pattern with a public constructor

我想将单例设计模式实现到 class,它在 PHP 中使用 public 构造函数扩展另一个 class。例如,考虑一个 class,比如 Animal:

class Animal
{

    public function __construct()
    {

    }
}

我想将单例设计模式实现到扩展 Animal 的 class,例如:

class Dog extends Animal
{

    protected function __construct()
    {
    }

    public static function getInstance()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new static();
        }

        return $instance;
    }
}

如果我尝试做 Dog::getInstance() 它会给出错误

Fatal error: Access level to Dog::__construct() must be public (as in class Animal)

但是如果我创建 class Dog public 的构造函数,那么对它实现单例模式就没有意义了。

是否有解决方法,以便我可以在扩展 class 动物的同时对 class 狗实施单例模式?或者是否有更好的设计模式来实现我想要的?

我无法修改 Animal,因为它属于图书馆。我可以完全控制 Dog。我真正想要实现的是 Dog 能够扩展 Animal,但我不想创建 Dog 的多个实例。

谢谢。

您可以将 Animal 声明为 interface,然后您可以将 Dog::__construct() 保持为受保护状态。

OR Is there a better design pattern for achieving what I want?

不清楚您希望通过实现单例实现什么 (anti-) pattern,尤其是在动物建模的上下文中,因此很难回答这个问题。目前我只能将数据库连接和注册表(会话)视为使用单例的可行用例(当然是在 Web 应用程序的上下文中)。

请看是不是你的正确答案。

class Animal
{

    protected function __construct()
    {
    }

    public static function getInstance()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new static();
        }

        return $instance;
    }
}

class Dog extends Animal
{
    function __construct()
    {
    }    
}  

@Havelock 感谢您提及(反)模式。我可以很容易地使用工厂模式实现我想要的东西。这是我的完整代码:

class Animal
{

    public function __construct()
    {

    }
}

class Dog extends Animal
{

    public function __construct()
    {
    }

    public function run()
    {
        echo 'The dog runs';
    }
}

class DogFactory
{

    public static function create()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new Dog();
        }

        return $instance;
    }
}

$d = DogFactory::create();
$d->run();

首先,单例模式不是反模式。它是为一个目的而制定的。如果你错过了目的,那么你就滥用了它。

针对您的问题: 扩展 class 使其成为单例没有任何意义。特别是如果 API 拒绝访问您遇到的构造。

我的建议: 支持组合而不是继承。所以创建一个没有继承的自己的 class 并应用单一模式。关联一个动物对象并将您想要的任何方法委托给该动物对象。