Php 单例类的构造
这是一个道德问题 我计划在我的新项目中使用几个经理类,它们将在整个项目中执行各种任务。这些类是单例类,但需要基于参数进行构造 至于何时/何地必须进行这种建设,我有复杂的感觉。到目前为止,我有以下选择: 选项A 只需将这些参数传递给Php 单例类的构造,php,constructor,singleton,Php,Constructor,Singleton,这是一个道德问题 我计划在我的新项目中使用几个经理类,它们将在整个项目中执行各种任务。这些类是单例类,但需要基于参数进行构造 至于何时/何地必须进行这种建设,我有复杂的感觉。到目前为止,我有以下选择: 选项A 只需将这些参数传递给getInstance方法,同时使用默认的null值,就很容易了。在第一次调用时,将使用这些参数,任何其他调用都会完全忽略它们 虽然这样做有效,但由于以下原因,这样做感觉相当不合逻辑: 它使文档不清晰。getInstance'第一个参数的类型必须是Collection
getInstance
方法,同时使用默认的null
值,就很容易了。在第一次调用时,将使用这些参数,任何其他调用都会完全忽略它们
虽然这样做有效,但由于以下原因,这样做感觉相当不合逻辑:
- 它使文档不清晰。
'第一个参数的类型必须是getInstance
,但可以是Collection
。。。这是怎么回事? 你可以争辩说,在描述中写一行关于这一点的话会让它变得清晰,但我更喜欢澄清而不是不必要的null
- 传递
任何构造参数都是错误的。这是因为方法名称没有明确地暗示构造,因此不清楚会发生什么getInstance
设置
方法。此方法获取所有参数,调用类构造函数,并将内部类状态更改为已初始化
在setup
之前调用getInstance
方法时,它将抛出NotInitializedException
。调用安装程序后,对setup
的任何其他调用都将导致先前初始化的异常
调用setup
后,getInstance
变为可用
就我个人而言,这个选择更吸引我。但感觉太过分了
你喜欢什么样的选择?为什么呢?选择3怎么样。如果它们是真正的单例,请为它们的参数设置属性文件,以便与no-arg getInstance一起使用
如果这不合适,您可能误用了单例模式。您正在考虑使用工厂设计模式。工厂是充当其他对象的奇特构造函数的对象。在您的情况下,您将把setup和getInstance移动到工厂。维基的文章很好-
我可能会尝试抛弃单例方法,将管理器类传递给任何需要它们的人
$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 );
不要使用单例,请使用资源管理器(或服务容器或DI容器):
资源管理器允许您为单元测试设置任何自定义类(如依赖项注入),您只需获得所需的资源,而无需在构造函数中请求它们(我喜欢DI,但有时使用空构造函数更方便)
随时可用的变量:(我不喜欢将逻辑从代码移动到配置,但在独立模块中,它看起来是可以接受的)。使用依赖项注入来传递管理器
对象。不要使用单例模式。人们普遍认为,使用它会创建一个全局状态,并使API具有欺骗性
通过构造函数将管理器
实例注入任何需要它的类。每个类都不应该尝试自己实例化管理器
,类获取管理器
实例的唯一方法是从构造函数获取它
class NeedsManager
{
protected $manager;
public function __construct(Manager $manager)
{
$this->manager = $manager;
}
}
您不需要强制执行管理器的一个实例。只是不要多次实例化它。如果所有需要Manager
实例的类都从构造函数中获得了所需的内容,并且从未尝试单独实例化它,那么它将确保应用程序中只会有一个实例。这不是单例,因为您可以编写$instance=new SingletonFoo()$instance2=new SingletonFoo()
-根据定义,单例仅允许存在于一个实例中。正确。我应该对代码进行更多的验证——我试图说明工厂而不是单例。我知道工厂设计模式。不过谢谢你指出这一点。我确实喜欢用一个类来管理一次性构造的想法,但我确实觉得ManagerManager类有点过头了。你可以将工厂方法移到类本身中,但对我来说,这模糊了类应该负责的范围。再一次-1您可以使用singleton类i作为过程代码的包装器,如果您对工厂使用静态方法,则可以基于类名创建依赖项。糟糕的做法。我以前确实考虑过这一点。虽然这在我的库中可以很好地工作,但我认为这将使使用它的开发人员的工作变得更加困难。他们必须在他们的应用程序中传递我的manager类,这将给尝试将其集成到现有应用程序中带来不便。此外,管理器类永远不需要多个实例。你可以说开发人员应该意识到这一点,并采取预防措施,但我觉得这是我的库的责任,而不是使用它的开发人员。@jrs:Never-need和cant-handle是两件截然不同的事情。如果他们从来都不需要,就让他们来处理。如果它不能处理它,看看你是否可以修复它(是的,我知道我没有提供关于后者的帮助;):观看视频并learn@teresko我完全同意所说的话。然而,我担心这一原则会给将库集成到现有应用程序中带来很多困难。想象一个简单的MVC框架。当您想要调用manager类上的方法时,需要对其进行完全初始化。您必须在最高级别进行实例化,将实例传递给请求处理程序,请求处理程序将实例传递给控制器工厂,而控制器工厂在
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;
}
}
class NeedsManager
{
protected $manager;
public function __construct(Manager $manager)
{
$this->manager = $manager;
}
}