扩展单例类

5

我曾经这样创建一个单例类的实例:

$Singleton = SingletonClassName::GetInstance();

对于非单例类:

$NonSingleton = new NonSingletonClassName;

我认为我们不应该区分创建类的实例是单例还是非单例。如果从其他类的角度来看,我并不关心我们需要一个单例类还是非单例类。因此,我仍然对PHP如何处理单例类感到不舒服。我想写出以下代码:

$Singleton = new SingletonClassName;

只是另一个非单例类,有没有解决这个问题的方法?


1
这不是一个问题,而是你抱怨你不喜欢模式的实现方式。-1 - Amy B
1
这是一个非常合理的问题。+1 因为 -1 不是 :P - Leo
5个回答

3

最好是反过来 - 为非单例提供工厂方法,并使用以下方式获取它们的实例:

$NonSingleton = NonSingletonClassName::createInstance();

这是Java的推荐最佳实践(见Effective Java),但它适用于大多数面向对象的语言。

2
我不建议这样做,因为这会使您的代码变得更难理解(人们认为new意味着一个全新的对象)。但是我也不建议使用Singletons。
这段代码的基本思想是,在Singleton周围包装了一个包装器。所有通过该包装器访问的函数和变量实际上都会影响Singleton。这并不完美,因为下面的代码没有实现很多魔术方法和SPL接口,但如果需要,它们可以被添加进去。 代码:
/**
 * Superclass for a wrapper around a singleton implementation
 *
 * This class provides all the required functionality and avoids having to copy and
 * paste code for multiple singletons.
 */
class SingletonWrapper{
    private $_instance;
    /**
     * Ensures only derived classes can be constructed
     *
     * @param string $c The name of the singleton implementation class
     */
    protected function __construct($c){
        $this->_instance = &call_user_func(array($c, 'getInstance'));
    }
    public function __call($name, $args){
        call_user_func_array(array($this->_instance, $name), $args);
    }
    public function __get($name){
        return $this->_instance->{$name};
    }
    public function __set($name, $value){
        $this->_instance->{$name} = $value;
    }
}

/**
 * A test singleton implementation. This shouldn't be constructed and getInstance shouldn't
 * be used except by the MySingleton wrapper class.
 */
class MySingletonImpl{
    private static $instance = null;
    public function &getInstance(){
        if ( self::$instance === null ){
            self::$instance = new self();
        }
        return self::$instance;
    }

    //test functions
    public $foo = 1;
    public function bar(){
        static $var = 1;
        echo $var++;
    }
}

/**
 * A wrapper around the MySingletonImpl class
 */
class MySingleton extends SingletonWrapper{
    public function __construct(){
        parent::__construct('MySingletonImpl');
    }
}

示例

$s1 = new MySingleton();
echo $s1->foo; //1
$s1->foo = 2;

$s2 = new MySingleton();
echo $s2->foo; //2

$s1->bar(); //1
$s2->bar(); //2

1

你不能像创建普通类实例一样创建单例。 new始终会返回新的实例,因此您必须将构造函数设置为非公共的,并且必须有另一种方式从类内部调用它。

您可以在所有类上拥有工厂方法,例如始终使用像另一个答案中所示的getInstance()。另一个选择是使用服务定位器依赖注入框架,它知道是否返回什么。


1

基于 new 关键字的含义,你想要什么都不重要。 new 创建一个类的新实例,这就是为什么它被命名为 new :-)


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接