views:

114

answers:

5

I know that Singleton pattern is bad because it uses global state. But in most applications, you need to have a single instance of a class, like a database connection. So I designed my Database object without using the singleton pattern but I instanciate it only once.

My question is, how can I access my object in the low level classes (deep in the object graph) without passing it all over the place?

Let's say I have an application controller which instanciates (ask a factory to instanciate it actually) a page controller which instaciates a User model which requires the database object.

Neither my app controller nor my page controller need to know about the database object but the User class does. How am I suppose to pass the object to it?

Thanks for your time!

+4  A: 

Consider using a global container:

  • You register the objects that are indeed relevant to the several subsystems of the application.
  • You then request that container those objects.

This approach is very popular in dependency injection frameworks (see Symfony DI, Yadif).

Artefacto
A global container is just a weakly typed Singleton, an even worse anti-pattern: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
Mark Seemann
@Mark This is a PHP question, there are no compile time typing errors, and only an optional run-time check when calling functions/methods.
Artefacto
I've already think about that actually. I could put all my singletons into a class named, say ApplicationScope and then use this class in my Factories to access my singletons. But it justs move the problem somewhere else, doesn't it? Now I'll have to pass ApplicationScope all over the place. Doesn't it break the Law of Demeter?
Alfwed
I guess my real question is : Where the glue code begins and where the business logic begins? Is a Controller considered as being glue code? If yes, I can use the solution you mentionned
Alfwed
I finally did something similar to what you describe. Thanks for your answer.
Alfwed
A: 

The way I've always accomplished this is to implement a static getInstance function that will return a reference to the single instance of that class. As long as you make sure that the only way you access the object is through that method, you can still ensure that you only have one instance of the singleton. For example:

class deeply_nested_class {

public function some_function() {

$singleton = Singleton::getInstance();

}

}

Chris Henry
+2  A: 

Singleton is bad, no doubt about it.

In the case you describe, the database object is an implementation detail of the User object. The layers above need only know about the User, not the database object.

This becomes much more apparent if you hide the user object behind an interface and only consume that interface from the layers above.

So the page controller should deal only with the interface, not the concrete class that depends on the database object, but how does in create new instances? It uses an injected Abstract Factory to create instances of the interface. It can deal with any implementation of that interface, not only the one that relies on a database object.

Once more, you hide the page controller behind an interface. This means that the concrete implementation's reliance on the Abstract Factory becomes another implementation detail. The Application Controller only consumes the page controller interface.

You can keep wrapping objects like that like without ever needing to pass around instances. Only in the Composition Root do you need to wire all dependencies together.

See here for a related answer with examples in C#: http://stackoverflow.com/questions/2386487/is-it-better-to-create-a-singleton-to-access-unity-container-or-pass-it-through-t/2386636#2386636

Mark Seemann
+1 You outline a good strategy, but I don't see how you actually address the question. At the point, the implementation of `User`, `Group`, or any other entity needs to get the database class. How do you suggest that's done? The factory implementation passes the constructor of the `UserImpl` (or injects via a setter)? I think that's the explicit "passing around" the OP wants to avoid.
Artefacto
It may be "passing around", but not "passing through" :) Each detail stays at the layer where it makes sense, but is hidden from the callers.
Mark Seemann
A: 

There are two main objects involved in loading/saving a user using the database: the user and the repository.

You seem to have implemented the functionality on the User, but I think it belongs on the Repository. You should pass the user to the Repository to save it.

But, how do you get hold of the Repository? This is created once at the top level and passed into services that need it.

The construction dependency graph and the call dependency graph are not the same thing.

WW
The User class is an exemple. I didn't say that I had such a class in my code base. Anyway, I know that I must pass dependencies to it. My question is How? I've already read almost all Misko's blog and he's anwser is "use Guice or Spring". I would like to know how to do DI by myself.
Alfwed
You do not need Guice or Spring to do dependency injection. Think of your application in two phases: a) First stage wires together services, b) Second stage runs. Services ask for what they need in the constructor. During a) they are all wired up and told about each other. During b) they call each other. You can use a factory to build everything in stage a). Better to start without Guice/Spring when doing this, even in java, to understand what is really happening.
WW
A: 

Given the example you outlined, you are almost there. You are already using a factory to instantiate your page controller, but your page controller is instantiating the users directly and as your User needs to know the database.

What you want to do is use a factory to instantiate your User objects. That way the factory can know about the database and can create User instances which know about it too. You will probably be better off making interfaces for all the dependencies, which will help with testing and will mean your code is nicely decoupled.

Create an IUserFactory which creates IUser implementations and pass this into your PageControllerFactory, then your ApplicationController only needs to know about the PageControllerFactory, it doesn't need to know anything about the IUserFactory or the database.

Then in your application start up you can create all of your dependencies and inject them in to each other through the constructors.

Sam Holder