Dependency Buffet

When I first read about depen­d­en­cy injec­tion, the pat­tern made total sen­se to me in a num­ber of ways. It fits the way I think about pro­blems and my men­tal model of desi­gning object rep­re­sen­ta­ti­ons of the stuff I am imple­men­ting. I’ve deci­ded to roll my own DI solu­ti­on, though, becau­se the­re are a few subt­le chan­ges that align even bet­ter with a few of my basic pre­mi­ses in pro­gramming.

When I wri­te code, I think about what I want to do and what I need to do that. When I wri­te a class that does data­ba­se stuff, I know it requi­res a data­ba­se con­nec­tion. I think this is infor­ma­ti­on that should be appa­rent in the class imple­men­ta­ti­on and nowhe­re else. So, what is more obvious to have the class know what it requi­res in the class its­elf? And this is how our Fac­to­ry class approa­ches this: it can ask a class it is just instan­tia­ting what it needs.

The code flow on instan­tia­ti­on is basi­cal­ly

  1.  we ask the Fac­to­ry for an object:
    $factory->giveme(’Car’);
  2. Fac­to­ry instan­tia­tes
  3. (see below)
  4.  Fac­to­ry asks the object
    $newObject->requireAssets()
  5. New­Ob­ject returns an array of assets that it needs
  6. Fac­to­ry keeps a list of regis­te­red assets (like an open and ready-to-use data­ba­se con­nec­tion) or knows how to find assets it does not yet have regis­te­red.
  7. Fac­to­ry also regis­ters its­elf as an asset with new­Ob­ject
  8. The new object is retur­ned to the cal­ler

One of the lovely side effects of this flow is that in most cases, we can eli­mi­na­te the need for sin­gle­tons; we can just open the data­ba­se con­nec­tion once and pass it on or we can regis­ter a cache once and have mul­ti­ple objects use it.

You may have rea­li­zed that we skip­ped a step on the first flow. Befo­re Fac­to­ry actual­ly asks new­Ob­ject what it requi­res, it pas­ses Con­text on. Con­text is – as the name implies – a collec­tion of infor­ma­ti­on about the cur­rent app­li­ca­ti­on in its envi­ron­ment. For ins­tan­ce, we have the name and class of the sys­tem we are run­ning on in the­re, or whe­ther it is an anony­mous ses­si­on or one of a log­ged-in user. By first kno­wing this, the object we are set­ting up gets to deci­de what it actual­ly requi­res befo­re it ans­wers the ques­ti­on. For ins­tan­ce, it may well be that an anony­mous ses­si­on does not requi­re a data­ba­se con­nec­tion whe­re a log­ged-in user will need that. So we addi­tio­nal­ly have:

3. Inject Con­text:
$newObject->setContext($context);

Ano­t­her thing that is important to me when I design stuff is to only keep around the stuff I need and only when I need it. I don’t think you should pull in all code of all libra­ries you use for every call. This means that some methods may need addi­tio­nal assets that other methods in the same class won’t need. By having Fac­to­ry as an asset, we can let tho­se methods ask for regis­te­red assets from our class hier­ar­chy at the time they need them; not when first initia­li­zing the object.

To have an asset, Fac­to­ry has a method registerAsset(name, asset). asset can be an object of the name of a class. If it is a class name that is regis­te­red, it will be instan­tia­ted the first time it is actual­ly requi­red and then also pas­sed on to other objects that also requi­re it. If our objects need new ins­tan­ces of a class, it is pos­si­ble to spe­ci­fy that at regis­tra­ti­on (becau­se it is more likely that the pro­vi­ding object knows about that).  To regis­ter an asset email­Tem­pla­te that will actual­ly pro­vi­de every object with a new email­Tem­pla­te, we need just to wri­te

$factory->registerAssetToInstantiate('emailTemplate', 'emailTemplate');

and are all set.

As a final fall­back, when Fac­to­ry is asked for an asset that it doesn’t know about, it just tri­es to instan­tia­te a class by that name.

Our Object class – which, as the name implies, is the par­ent class of most objects in our hier­achy – encap­su­la­tes the default beha­vi­or. It uses one pro­tec­ted varia­ble _requiredAssets that con­ta­ins the array of the assets the cur­rent class requi­res. And that way, we can just con­cen­tra­te on get­ting on with the stuff that the class is actual­ly about.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.