这是一个道德问题。
我打算在我的新项目中使用几个管理器类,这些类将在整个项目中执行各种任务。这些类是单例,但需要基于参数构建。
关于这种建筑何时/何地发生,我的感情很复杂。到目前为止我有这些选择:
选项A
在具有默认getInstance
值的情况下,将这些参数传递给null
方法很容易。在第一次调用时,将使用参数,并且任何其他调用都会完全忽略它们。
虽然这样做有效,但由于以下原因,这样做感觉相当不合逻辑:
它使文档不清楚。 getInstance
'第一个参数必须是Collection
类型,但可以是null
...发生了什么这里?
你可以争辩说,在描述中写下这一点会清除它,但我更愿意澄清是不必要的。
传递getInstance
任何构造参数感觉有问题。这是因为方法名称没有明确暗示构造,因此不清楚它是否会发生
选项B
我正在考虑使用setup
方法。此方法接受所有参数,调用类构造函数,并将内部类状态更改为initialized
。
在getInstance
之前调用setup
方法时,它会抛出NotInitializedException
。调用设置后,对setup
的任何其他调用都将生成PreviouslyInitializedException
。
调用setup
后,getInstance
可用。
就个人而言,这个选项对我更有吸引力。但感觉过度。
您更喜欢哪种选择?为什么?
答案 0 :(得分:2)
我可能会尝试抛弃单例方法并将管理器类传递给任何需要它们的东西。
$manager = new Manager( $collection, $var, $var2 );
$other_class = New OtherClass( $manager );
//or
$other_class = New OtherClass;
$other_class->manager = $manager;
//or
$other_class = New OtherClass;
$other_class->setManager( $manager );
答案 1 :(得分:1)
使用依赖注入来传递Manager
对象。不要使用Singleton模式。使用它会产生全局状态并使您的API具有欺骗性,这是一种普遍的共识。
通过构造函数将Manager
实例注入任何需要它的类。每个类不应该尝试自己实例化Manager
,类获取Manager
实例的唯一方法是从构造函数中获取它。
class NeedsManager
{
protected $manager;
public function __construct(Manager $manager)
{
$this->manager = $manager;
}
}
您无需强制执行Manager
的一个实例。只是不要多次实例化它。如果所有需要Manager
实例的类从构造函数中获取所需内容,并且从不尝试在自己的上实例化它,那么它将确保只有一个实例在你的申请中。
答案 2 :(得分:0)
选项3如何。如果它们是真正的单例,请为其参数设置属性文件,以便与no-arg getInstance一起使用。
如果不合适,可能会误用单例模式。
答案 3 :(得分:-2)
您正在考虑使用Factory设计模式。工厂是充当其他对象的花哨构造函数的对象。在您的情况下,您将setup和getInstance移动到工厂。维基文章非常好 - http://en.wikipedia.org/wiki/Factory_method_pattern
class SingletonFoo {
//properties, etc
static $singleton = NULL;
private function __constructor(){}
static function getInstance(){
if(NULL === self::$singleton) {
self::$singleton = new SingletonFoo();
}
return self::$singleton;
}
}
class FooFactory {
static $SingletonFoo = null;
static function setup($args){
if( !(NULL === self::$SingletonFoo)){
throw new AlreadyInstantiatedException();
}
self::$SingletonFoo = SingletonFoo::getInstance();
//Do stuff with $args to build SingletonFoo
return self::$SingletonFoo;
}
static function getInstance(){
if(NULL === self::$SingletonFoo) {
throw new NotInstantiatedException();
}
return self::$SingletonFoo;
}
}
答案 4 :(得分:-2)
不要使用Singleton,请使用Resources Manager(或Service Container,或DI Container):
class ResourceManager
{
protected static $resource;
public static function setResource($resource)
{
if (!empty(self::$resource)) //resource should not be overwritten
{
if ($resource!=self::$resource) return false;
else return true;
}
self::$resource = $resource;
return true;
}
public static function getResource()
{
return self::$resource;
}
}
资源管理器允许您设置任何自定义类进行单元测试(如依赖注入),您只需获取所需资源而无需在构造函数中请求它们(我喜欢DI,但有时候使用空构造函数会更方便)。
即用型变体:http://symfony.com/doc/current/book/service_container.html(我不喜欢将逻辑从代码转移到配置,但在独立模块中看起来可以接受)。