Dependency Injection Breaks Encapsulation

You keep going on about the fact that it’s YOUR CODE. We get that, but you also keep trying to post-rationalise your design decisions to us.

You come to US with some code or post it publicly. We critique it, as we would with any code and then you say “I DIDN’T WANT YOU TO ANALYSE IT! STOP TELLING ME WHAT TO DO!”

Can’t you read? I have already shown you code where I do NOT use DI such as

class Person {
    function doStuff () {
        ....
        $objAddress =& singleton::getInstance('Address');
        $address = $objAddress->getPrimaryAddress($customer_id);
        ....
    } // doStuff
} // end class Person

And I have explained why. All you can respond with is “you could use DI here, and here’s how”. Yes, I could use DI there, but I won’t for reasons that I have already explained.

The description “really need” is too vague. Using Robert C Martin’s “copy” program as a starting point I consider that DI is only beneficial

Listen, Tony, Don’t come here asking for advice or starting a discussion and then say “I DON’T WANT TO TALK ABOUT IT” it’s pointless and futile

Tony, here’s what I suggest you do. Preemptively: I’m not suggesting you rewrite your existing codebase or make any changes to it.

Start a brand new project, ignoring everything you currently have. Start from line 1 from scratch and build a very small project using the principles we’ve been describing including TDD, Law of Demeter, Dependency Injection and Composition over Inheritance. This will do several things that are useful for this discussion:

1) Help you better understand the concepts we're discussing
2) Better enable you with the knowledge needed to show why alternatives are better if you still truly believe so.
3) Give you an understanding of why relying on your existing antiquated codebase is not helpul for this discussion
4) Allow you to fully grasp the differences between the different approaches.

The problem is currently that you are unable to take a step away from your existing code and discuss the concepts on their own merit, you can only discuss them in terms of how they affect you personally because your code is written in such a way that these techniques cannot be used.

Your answer to this will be “I don’t want to”, which is fine, but it doesn’t leave any scope for further discussion.

I provided around 10 references for why this is bad. Singletons are problematic and so is breaking law of demeter. Unsurprisingly this discussion has gone full circle.

By your definition then, EVERY argument on a method would break encapsulation. This is patently false. Passing a string argument which is built into an SQL query is not the same as passing an object which contains methods which are to be called. The latter is affecting the implementation of that method in a far more serious way than a string argument, and by having an effect on the implementation you are exposing that implementation to the outside world. By violating the principle of implementation hiding you are therefore violating encapsulation

That Wikipedia article says the following:

[quote]
Encapsulation is the packing of data and functions into a single component. The features of encapsulation are supported using classes in most object-oriented programming languages, although other alternatives also exist. It allows selective hiding of properties and methods in an object by building an impenetrable wall to protect the code from accidental corruption.[/quote]
How is that wildly different from what I said?

No I am not. I am simply saying “this is how I do things and here are the reasons why”

No it’s not. You again choose to miss the point. An object argument is no different to a string argument. Both are encapsulated.

Because you said that “Passing an object into a constructor breaks encapsulation”. By the definition you just posted, how is that the case?

If you’re going to say that “The calling code knows about the implementation of the contstructor” again, then I refer you to my earlier point. Does this break encapsulation: new Person(123)? If so, so does $foo->bar(‘123’); or $person->eat($apple).

I don’t agree that $person->eat($apple). breaks encapsulation, I’m just trying to work out why you do.

In a public discussion forum… where you came seeking opinions… then got annoyed that they weren’t the opinions you wanted to hear.

It depends on why you are injecting an object into a constructor. If you are doing it simply because the rules of DI say that you must and not because you have a genuine reason, then by using DI in an inappropriate place you are breaking encapsulation by virtue of the fact that by telling the object how to implement a certain function you are unhiding that implementation, and implementation hiding is what encapsulation is all about, isn’t it?

I disagree. You are telling the Person object to retrieve some data, but also telling it which object to use for any ancillary data. If that ancillary data can only come from a single object then there is no need to provide the ability to switch it to another object. This is a prime example where DI is employed in circumstances where there are no benefits.

I am not going to keep repeating what I have already said. It is up to you to read what I have said.

I was referring to what you wrote in post #17 which referred to $this->bar->x() and said

[quote]
It also knows about the implementation of the Bar instance. (That it has a method called X). This is known as a law of demeter violation.[/quote]
The fact that I know that bar has a method called X is not a problem.

Please for once read some of the references I post. If nothing else, this post: http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/

The problem is you’re confusing “Tight coupling” and “Encapsulation”. Encapsulation is not Tight Coupling, and tight coupling is actually a bad thing.

See:

http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx
http://crazycoders.net/from-tight-coupling-to-dependency-inversion-stupid-series/
http://codebetter.com/jeremymiller/2009/01/06/it-s-been-years-since-i-ve-gone-on-an-anti-singleton-rant/
https://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html

Once again you don’t provide references, your arguments rest entirely on “My opinion is right”.

Oh “You Disagree” What a compelling argument you present. I’ll just leave this with [citation needed] and a few references of my own that demonstrate otherwise:

http://misko.hevery.com/2008/11/11/clean-code-talks-dependency-injection/
https://msdn.microsoft.com/en-us/magazine/cc163739.aspx
http://martinfowler.com/articles/injection.html

So new Person(new Address) isn’t problematic? I’m glad that’s settled.

I am not lying. If you read what I wrote you would see that what I actually say is:

DI breaks encapsulation - under some circumstances
DI is evil - under some circumstances.

On a public discussion forum, where you are dissuading people from using DI and then getting upset whenever someone tells you you’re wrong…

That is the whole purpose of this discussion - to identify when it is appropriate to use DI and when it is not. All you keep repeating is that it is never inappropriate to use DI, and this is where I have to disagree. I am trying to present logical arguments, but you keep twisting everything I say.

I thought I’d elaborate on this a bit, as it’s an important distinction. Both of the following examples use encapsulation. The engine is stored inside the Car object, and when the car accelerates, it uses the engine. The difference is tight and loose coupling.

In either case, whenever the car accelerates, the engine is started.

Tight coupling


class Car {	
	public function __construct() {
		$this->engine = new Engine;
	}

	public function accellerate() {
		$this->engine->start();
	}

}

Loose coupling

class Car {	
	public function __construct(Engine $engine) {
		$this->engine = $engine;
	}

	public function accellerate() {
		$this->engine->start();
	}

}

The step that you seem to be missing here is an important one: Objects are not usually created and used in the same place. For example:

class Driver {
	
	public function drive(Car $car) {
		$car->accellerate();
	}
}

In the calling code, with either the loosely coupled, or tightly coupled car implementation the result is identical: The driver has no knowledge of the engine, only the car because the engine is encapsulated in the Car object.

I am not asking for advice on how to use DI, I am asking the question “under what circumstances is DI an inappropriate solution?” All you can do is say “there are NO circumstances where DI is inappropriate”. That does not leave any scope for further discussion.

Actually I’m saying “Show me a situation where another approach is preferable to DI” and you have repeatedly failed to do so. You present singletons, which have been widely discredited for about 10 years as an answer which is utterly pointless as there’s no room for discussion on them. The debate was had over 10 years ago by people far smarter than you or I and singletons lost hands down.

But you still haven’t provided arguments against my reasons for NOT using DI. Pointing me to articles which support your case is a waste of time as I can point to an equal number of artoicle which do the opposite.

singletons are only problematic - in certain circumstances.

As for the law of Demeter - I prefer the Inverse Marmalade law.

The arguments for using DI is that the alternatives are objectively worse because they break all sorts of important programming principles. Law of Demeter and Global State being the two main ones.

Given the two approaches, DI is objectively better because your approach breaks these fundamental principles that create known bad traits. I don’t see how there is any discussion here and you’re not backing up your points with anything more meaningful than “Because i said so” or “I don’t want to”.