4

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!

Charles
  • 50,943
  • 13
  • 104
  • 142
Alfwed
  • 3,307
  • 2
  • 18
  • 20
  • 2
    Honestly, this is probably a case where the singleton pattern *would* be appropriate. – Amber Jul 24 '10 at 20:28
  • @Alfwed: I agree with @Amber. keep in mind that although in *general* Singletons are bad because of the global state thing, in web programming with PHP, it crops up quite a lot, because a lot of objects there is **only one of**, like Databases, Requests, Responses, Sessions, etc. This is where you *would* want to use a Singleton, because you need to ensure you only ever have one specific, global instance. – Austin Hyde Jul 24 '10 at 23:23
  • @Austin It is simple to ensure you have only one instance of a class : just call the new operator once. Your anwser isn't relevant to me – Alfwed Jul 26 '10 at 13:05
  • @Alfwed: First, it wasn't an answer, it was a comment. If it was a relevant answer, I would have posted an answer. Second, yes, you can only call the new operator once, but in terms of a semantic interface, it means you can instantiate as many as you want, invalidating the idea behind a Singleton - having a single global instance of a class. – Austin Hyde Jul 26 '10 at 15:13

5 Answers5

4

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
  • 96,375
  • 17
  • 202
  • 225
  • 2
    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 Jul 24 '10 at 22:55
  • @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 Jul 25 '10 at 00:12
  • 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 Jul 25 '10 at 10:05
  • 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 Jul 25 '10 at 10:08
  • I finally did something similar to what you describe. Thanks for your answer. – Alfwed Jul 28 '10 at 09:40
2

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#: Is it better to create a singleton to access unity container or pass it through the application?

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • +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 Jul 25 '10 at 00:17
  • 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 Jul 25 '10 at 07:07
0

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
  • 11,914
  • 3
  • 30
  • 31
0

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.
  • 23,793
  • 13
  • 94
  • 121
  • 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 Jul 26 '10 at 10:37
  • 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. Jul 26 '10 at 23:42
0

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
  • 32,535
  • 13
  • 101
  • 181