如何避免在整个地方传递上下文对象?

时间:2011-09-27 10:43:15

标签: php oop design-patterns

  

可能重复:
  Dependecy Hell - how does one pass dependencies to deeply nested objects

最近我一直在努力解决这个特殊问题。为了测试和管理原因,我认为将$ config这样的对象注入需要它的人是一个更好的选择。虽然在开始时它没关系,后来它开始污染代码。 例如: 对象A使用对象B来完成它的工作,对象B使用策略对象C,对象C使用对象D,它需要$ config对象。所以,我必须继续将$ config传递给整个链

在我的代码中,我有两个像这样的对象通过,这使得构造函数很大,有重复的代码,通常它闻起来有些错误。 我很感激任何帮助重构这种关系。

3 个答案:

答案 0 :(得分:2)

而不是(伪代码作为一般建议)......

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)

答案 1 :(得分:0)

我是否认为$ 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);

?>

您将看到两个'实例'都包含值为'abc'的'property',因为它们实际上都是同一个实例。如果你已经熟悉这种技术,我很抱歉,但这听起来肯定是你要找的东西!

修改

如下所述,这仍然可以克隆。如果你真的想要防止这种情况发生,你必须覆盖魔术方法__clone()来阻止这种情况发生。然而,序列化观察只是迂腐。

答案 2 :(得分:0)

您似乎需要使用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();

没有在调用堆栈中传递它而不依赖于全局变量。

注册表具有类似的工作方案,但允许您创建一种注册表,因此需要提供对象的名称。