单例模式最佳实践

项目有个类需要使用单例模式,这我熟悉啊,眨眼之间就写了如下代码

class A
{
    protected static $instance = null;
    
    // 防止外部实例化
    protected function __contruct(){}
    // 防止克隆
    protected function __clone(){}

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
       
        return self::$instance;
    }
   
    //todo
}

写完了,可以回家了,不过凭我多年写代码第六感的直觉,我隐约觉得好像哪里不对,瞟了一眼老司机的代码,如下

class A
{
    protected static $instance = null;

    // 防止外部实例化
    protected function __contruct(){}
    // 防止克隆
    protected function __clone(){}

    public static function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static();
        }
       
        return static::$instance;
    }
   
    public function say()
    {
        echo 'I am A'.PHP_EOL;
    }
}

看似一样,实则暗藏玄机,关键就在new static(),你可能会说这个我知道,后期静态绑定,如果你这么认为,那么我只能说,恭喜你,答对了。如果你不知道这是啥,没关系,请看这里
可是why要这么写呢,我脑海中出现了柯南后脑勺的那道闪电,继承。看下面代码

class A
{
    protected static $instance = null;

    // 防止外部实例化
    protected function __contruct(){}
    // 防止克隆
    protected function __clone(){}

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
       
        return self::$instance;
    }
   
    public function say()
    {
        echo 'I am A'.PHP_EOL;
    }
}
   
class B extends A
{
    public function say()
    {
        echo 'I am B'.PHP_EOL;
    }
    
    public function test()
    {
        echo 'B test'.PHP_EOL;
    }
    
}

$b = B::getInstance(); //$b是类A的实例
$b->test();

运行结果

PHP Fatal error:  Uncaught Error: Call to undefined method A::test()

$b是类A的实例,但是我们需要类B的实例,使用new static()的话,B::getInstance()得到类B的实例,这对应后期静态绑定的非转发调用(non-forwarding call)

在tp和laravel框架中,Container类是这样实现的单例,这种写法我觉得从语义上更清晰一些,但是功能上是一样的。

**
* Set the globally available instance of the container.
*
* @return static
*/
public static function getInstance()
{
    if (is_null(static::$instance)) {
        static::$instance = new static;
    }

    return static::$instance;
}
posted @ 2020-09-23 23:53  whyly  阅读(175)  评论(0编辑  收藏  举报