How do I avoid passing a context object everywhere?

Possible duplicate:
Dependecy Hell - how to skip dependencies on deeply nested objects

Recently, I have been struggling with this particular problem. For testing and managing the reasons, I decided that it would be the best option for entering an object, such as $ config, to those who need it. Although this was normal at the beginning, he later began to foul the code. For example: Object A uses object B to do its job, object B uses strategy object C, object C uses object D, which needs $ config object. So, I have to keep passing $ config all along the chain

In my code, I have two objects that need to go through, which makes the constructors large, with duplicate code and, as a rule, it smells bad. I would appreciate any help in refactoring this relationship.

+4
source share
3 answers

Instead (pseudo code as general advice) ...

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) } 

you should convey only what is really necessary:

 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 } 

You have as local a state as possible. The global state is at the root of an indefinite number of debugging horror scenarios (since I feel like you just ran into it).

As an alternative to many classes, you don’t need to know what their objects look like, they are just interested in the open interface. You can apply dependency inversion, then:

 config <-- ... objectC = createC (config.frobnicate) objectB = createB (config.frob, objectC) objectA = createA (config.foo, config.bar, objectB) 

Using dependency inversion means freeing your classes from having to know too much. For example, a Car does not need to know about Trailer and its composition, it just needs to know about CouplingDevice :

 trailer = createTrailer (...) couplingDevice = createCouplingDevice (...) car.install (couplingDevice) couplingDevice.attach (trailer) 
+2
source

I understand correctly that $ config contains ... well, the configuration information required by most of your application? If so, it looks like you should consider (universally) a singleton design pattern.

If you are not already familiar with it, this is a method that allows you to use only one instance of the class at runtime of your application. This is very useful when storing the values ​​of the entire application environment, since you do not risk creating an instance of the second object; and you do not bypass the "copy" of objects.

As an example, consider the following:

 <?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); ?> 

You will see that both instances contain a β€œproperty” with a value of β€œabc”, since both of them are actually the same instance. I apologize if you are already familiar with this technique, but it certainly looks like what you are looking for!

Edit

As indicated below, this can still be cloned. If you really wanted to prevent this, you would have to override the __clone () magic method to stop this. However, watching serialization is just pedantic.

0
source

It looks like you need to use singleton or registry templates.

A singleton consists of a class (with a private constructor) that can be created by the static method to get the same object (forgive me for simplification) every time you need it.

Follow this pattern:

 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 

}

This way you can get the desired object where you need it, with something like

 $config = Config::getInstance(); 

without passing it to the call stack, without resorting to global variables.

There is a similar workflow in the registry, but you can create a kind of registry and therefore the name of the objects you need to do.

0
source

All Articles