Hi Rohit!
I'm assuming that by dependency injection you mean passing in a collaborator to an object, rather than the object creating the collaborator itself. And at least two ways I know to do this is either passing in the dependency via the constructor or via a method parameter.
I find that using dependency injection can help me separate how an object works from how it is constructed. That is, if I'm building some object, say a newsletter distribution service that needs to collaborate with something that can get send e-mails over SMTP, I can pass that SMTP-speaking object into the constructor as a collaborator. Then I can worry about all the messy connection and mail session lifecycle into other objects. This means there is less code in my object, the code can focus on solving my problem domain (distributing newsletters to subscribers) instead of intermixing SMTP and connection code all in one place. This usually means the code is easier for me to understand later. I can pass in an alternate collaborator in my tests if it's the real thing is hard to work with. And when I start thinking about alternate testing versions of the collaborator, I can also start thinking of alternative implementations in the production code that might be useful as well. For example, an implementation of the mail sender that does nothing but prints what it would have sent -- a "dry-run" feature, for example.
The disadvantage I've found to using dependency injection is that I can err on the side of passing in *too many* dependencies, creating code that is equally hard to test and understand. What I've learned from GOOS is that some collaborators might be peers of the object and have other uses in my system, and some objects are truly implementation details and can be created and managed entirely by the object. GOOS calls these objects "internals".
Is this what you were asking about, Rohit?
Cheers,
Dan