You know what tony, I’ll help you out in order to try to progress this discussion in a meaningful way. As you’re finding it so incredibly difficult to make your own point, I’ll try to steer you towards something that isn’t meangingless by giving you a 3 step template to follow. I’ll restate my argument in the manner I’m asking you to, I think that’s only fair. (I have done this several times already but hopefully another demonstration will help). Note that all code examples are complete, can be run and do not rely on anything else and contain only code relevant to the concept being demonstrated.
Please make your point by:
- Providing some example code that uses DI
- Providing some example code that achieves the same result without using DI where an improvement has been made
- Explain briefly the metrics you are using you measure that improvement.
Here, I’ll start:
###1) Here is an example of using DI. Note that this code is minimal and contains only code that is relevant to the concept I am trying to convey.
class A {
private $b;
public function __construct(B $b) {
$this->b = $b;
}
public function doSomething() {
$x = $this->b->x();
}
}
new A(new B);
2) Here is an example using Tony Marston’s singleton class to achieve the same result:
class Singleton {
private static $instances = [];
public static getInstance($name) {
if (!isset(self::$instances[$name])) {
self::$instances[$name] = new $name;
}
return self::$instances[$name];
}
}
class A {
public function doSomething() {
$b = singleton::getInstance('B');
$x = $b->x();
}
}
new A;
3) Reasons that (1) is better than (2)
- Less code therefore less scope for bugs
- Less code therefore easier to read
- Lower memory usage
- Lower execution time due to fewer lines of code being executed
- In (2) it’s impossible to instantiate B if it has different constructor args to anything else managed by the singleton
- In (2) the singleton must know about the dependencies of any class it instantiates
- In (2) there is no way to use a subclass or different implementation of the B class unless I add some logic to the singleton, however that will affect any other place where B is requested
- (1) does not suffer a law of demeter violation. I’m not going to explain why that’s good but see here: http://misko.hevery.com/code-reviewers-guide/flaw-digging-into-collaborators/
- (2) is not portable. To move it to another project I must move all the singleton and all the classes the singleton knows about (and all the classes those know about, and all the ones they know about, ad infinitum)
- (1) doesn’t rely on global state. This means I can create two instances of A that use different instances of B, alternatively I have the option to use either the same instance or a different instance each time.
- In (2) if I want to move the A class to a different project I have to look through the class line by line and read the implementation of the singleton class to work out which other classes I need to copy to the new Project. In (1) I only have to look at the constructor.
- As above but in (2) I need to move 3 classes (A, B and the Singleton class) into the new project adding extra weight. In (1) I only need to move two (and I can immediately work out which two)
- (2) is harder to understand and follow for a new developer. If I look at the A::doSomething() method I cannot know what methods are available on the $b variable without looking into the singleton::getInstance() class and finding out what class it returns. In (1) I simply look at the constructor and know what class/interface is being used.
- (1) can be isolated for testing
- (1) Allows me to instantiate the A object with any subclass of B. This means my subclasses can have their own set of unique dependencies and A doesn’t need to know about them. In (2) this is impossible.
Disclaimer. Please read
I want to be clear because I know what you’re going to do: I’m not asking you to debate my points in section 3 I am asking you to make an argument using the same 3 step structure. Once you have demonstrated your approach and the benefits of it, only then can we compare those benefits relative to one another.
If you actually have a valid argument or a point to make, this should be an incredibly easy request to respond to. If you don’t do this, you are are admitting you cannot.