假设我有一个非常普通的课程:
class Money
{
public __construct($actualCountry)
{
$this->actualCountry = $actualCountry;
}
public function getValute()
{
return according to actual country
}
}
这个类需要创建一次,所以我有一个全局工厂:
final class Factory
{
private $money;
public function getMoney()
{
if ($this->money == null)
{
$this->money = new Money(Config::getCountryCode());
}
return $this->money;
}
}
每当我们想要使用时:
Factory::getMoney()->
但今天我看到我的同事试图这样做:
(new Money(Config::getCountryCode()))->getValute();
这显然是错误的,不需要多次出现。但那么一个班级本身怎么说“嘿,不要实例化我,使用工厂”?
我无法将其设置为单身,因为每次都是:
Money::getInstance(Config::getCountryCode());
没有意义。
但真正的问题并不是因为它可能存在多个 - 这就是我总是从配置中传递当前国家的方式。什么是Config
成为GlobalConfig
?这就是为什么工厂要避免大量的参数传递(如果Money
会有更多的参数怎么办?)
答案 0 :(得分:3)
我认为你应该再考虑一下Singleton模式。它更适合你想要的逻辑。
<?php
class Money
{
private static $instance;
private function __construct($countryCode)
{
#your code here...
}
/**
* Do not include parameter for getInstance.
* Make the call internally.
* Now when you have to change Config to GlobalConfig will be painless.
*/
public static function getInstance()
{
if (null === self::$instance) {
return self::$instance = new Money(Config::getCountryCode());
}
return self::$instance;
}
}
答案 1 :(得分:2)
您可以将构造函数设置为private或protected以防止直接实例化。 (参见提及单身模式的其他答案)。
如果你不能/不想使用单例模式,你必须接受构造函数是公共的,或者使用一些闭包绑定魔法来绕过它。
免责声明:这只是一个概念证明。我不会在任何生产代码中使用它。在PHP支持名称空间/类可见性/朋友类之前,没有很好的方法可以实现这一点。
class Factory
{
private static $money;
static function getMoney()
{
if (null === self::$money) {
self::$money = self::createInstance('Money', [Config::getCountryCode()]);
}
return self::$money;
}
private static function createInstance($class, array $args)
{
// bind a closure to the given class and call it
return call_user_func(Closure::bind(function () use ($class, $args) {
// create a new instance without calling the constructor
$object = (new ReflectionClass($class))->newInstanceWithoutConstructor();
// call the constructor manually from this context (which has access to it now)
call_user_func_array([$object, '__construct'], $args);
// return the constructed object
return $object;
}, null, $class));
}
}
使用工厂:
var_dump(Factory::getMoney());
输出:
对象(金钱)#3(1){ [ “actualCountry”: “金钱”:私人] =&GT; string(10)“some_value” }
尝试直接实例化
输出:
new Money();
致命错误:从...在线...
中的无效上下文调用私有Money :: __ construct()
答案 2 :(得分:1)
没有办法完全阻止外部实例化,因为要使Factory工作,构造函数必须直接或间接地公开访问。
您可以通过将构造函数设置为私有来隐藏构造函数,并向类中添加静态工厂方法:
class Money
{
private function __construct($actualCountry)
{
$this->actualCountry = $actualCountry;
}
public static function fromFactory($actualCountry)
{
return new static($actualCountry);
}
public function getValute()
{
// return according to actual country
}
}
final class Factory
{
private $money;
public function getMoney()
{
if ($this->money == null)
{
$this->money = Money::fromFactory(Config::getCountryCode());
}
return $this->money;
}
}
或者你可以改变构造函数以要求一个(类型的)第二个参数,这是工厂使用的。但是,如果您的工厂使用静态方法,这将不起作用,就像在您的示例中一样:
class Money
{
public function __construct($actualCountry, Factory $factory)
{
$this->actualCountry = $actualCountry;
}
public function getValue()
{
// return according to actual country
}
}
final class Factory
{
private $money;
public function getMoney()
{
if ($this->money == null)
{
$this->money = new Money(Config::getCountryCode(), $this);
}
return $this->money;
}
}
答案 3 :(得分:0)