可能重复:
Dependency Hell-如何将依赖关系传递给深度嵌套对象
最近我一直在努力解决这个特殊的问题。出于测试和管理的原因,我决定向需要的人注入$config这样的对象会是一个更好的选择。虽然一开始还可以,但后来它开始污染代码。例如:对象A使用对象B来完成它的工作,对象B使用策略对象C,对象C使用对象D,对象D需要$config对象。所以,我必须不断地把$config传给整个链
在我的代码中,我有两个类似的对象要通过,这使得构造函数很大,有重复的代码,而且通常闻起来是错误的。如果能为重构这种关系提供任何帮助,我将不胜感激。
代替(伪代码作为一般建议(。。。
config <-- ...
A.constructor (config) {
this.foo = config.foo
this.bar = config.bar
this.objectB = createB (config)
}
B.constructor (config) {
this.frob = config.frob
this.objectC = createC (config)
}
C.constructor (config) {
this.frobnicate = config.frobnicate
this.objectD = createC (configD)
}
你应该只通过真正需要的:
config <-- ...
A.constructor (foo, bar, frob, frobnicate) {
this.foo = foo
this.bar = bar
this.objectB = createB (frob, frobnicate)
}
B.constructor (frob, frobnicate) {
this.frob = frob
this.objectC = createC (frobnicate)
}
C.constructor (frobnicate) {
this.frobnicate = frobnicate
}
让你所在的州尽可能地本地化。全局状态是无数调试恐怖场景的根源(我听说你刚刚遇到过(。
或者,许多类不必知道它们的对象是什么样子的,它们只对公共接口感兴趣。您可以应用依赖反转,然后:
config <-- ...
objectC = createC (config.frobnicate)
objectB = createB (config.frob, objectC)
objectA = createA (config.foo, config.bar, objectB)
使用依赖反转意味着让类不需要知道太多。例如,一个Car
不需要知道Trailer
及其组成,它只需要了解CouplingDevice
:
trailer = createTrailer (...)
couplingDevice = createCouplingDevice (...)
car.install (couplingDevice)
couplingDevice.attach (trailer)
看起来您需要使用singleton或注册表模式。
singleton由一个类(带有私有构造函数(组成,该类可以通过静态方法创建,以便在每次需要时获得相同的对象(请原谅我的简化(。
它遵循这个方案:
class Config {
static private instance=null;
private function __constructor() {
// do your initializzation here
}
static public function getInstance() {
if (self::instance==null) {
self::instance== new Config();
}
return self::instance;
}
// other methods and properties as needed
}
通过这种方式,你可以用之类的东西在需要的地方获得所需的对象
$config = Config::getInstance();
而不用在调用堆栈中传递它,也不用求助于全局变量。
注册表有一个类似的工作方案,但允许您创建一种注册表,从而为需要提供的对象命名。
我认为$config包含。。。那么,您的应用程序的大部分都需要的配置信息?如果是这样的话,听起来你应该考虑(无处不在的(单例设计模式。
如果您还不熟悉它,那么它是一种在应用程序的整个运行时只允许类的一个实例的技术。这在维护应用程序范围的值时非常有用,因为您不会冒实例化第二个对象的风险;也没有传递对象的"副本"。
例如,检查以下内容:
<?php
class Test {
private static $instance;
private function __construct() { } // Private constructor
static function instance() {
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
}
$a = Test::instance();
$b = Test::instance();
$a->property = 'abc';
var_dump($a->property);
var_dump($b->property);
?>
您将看到两个"instance"都包含值为"abc"的"property",因为它们实际上都是同一个实例。如果你已经熟悉这个技巧,我很抱歉,但这听起来确实是你想要的东西!
编辑
正如下面所指出的,这仍然可以被克隆。如果你真的想防止这种情况发生,你必须重写魔术方法__clone((来阻止这种情况的发生。不过,序列化观察只是迂腐。