The principles you speak of are generally applicable to any OO language. The basic tenet here is "loose coupling". A class that depends upon another class (contains an instance of it and calls methods on it as part of its own work) really only depends on a set of functionality the dependency provides. If the class defines a reference to a concrete class that it depends on, and you then want to replace the class with another, you not only have to develop the new class, but change the dependent class to depend on the new type. This is generally bad, because if your class is depended on by many other classes, you have to change code in multiple places, requiring you to test all the use cases involving those objects to ensure you haven't broken previously-working functionality.
Interfaces were designed to eliminate this, allowing multiple classes that are unrelated by ancestry to be used interchangeably based on a common, enforced set of methods that you know a class will implement. If, instead of depending on a class, you depended on an interface, any class implementing the interface would fulfill the dependency. That allows you to write a new class to replace an old one, without the class that uses it knowing the difference. All you have to modify is the code that creates the concrete implementation of the class filling the dependency.
This presents a quandary; sure, your class Depender can say it needs an IDoSomething instead of a DoerClass, but if Depender knows how to create a DoerClass to use as the IDoSomething, you haven't gained anything; if you want to replace DoerClass with BetterDoer, you must still change Depender's code. The solution is to give the responsibility for giving the class an instance of a dependency to a third party, a Creator. The class chosen for this depends on the context. If a class naturally has both Depender and DoerClass, it's the obvious choice to use to put them together. This is often the case when you have one class that has two helper dependencies, and one dependency needs the other as well. Other times you may create a Factory, which exists to provide the caller with an instance of a specific object, preferably with all dependencies hooked up.
If you have several interdependent classes, or dependencies many levels deep, you may consider an IoC framework. IoC containers are to Factories as Repositories are to DAOs; they know how to get you a fully-hydrated instance of ANY class requiring one or more dependencies, like a Repository can produce any fully-hydrated domain object from data in the DB. It does this by being told what concrete class should be used to fill a dependency in a certain situation, and when asked to provide a class, it will instantiate that class, providing instances of the required dependencies (and dependencies of dependencies). This can allow patterns where Class A depends on B, which depends on C, but A cannot know about C. The IoC framework knows about all three, and will instantiate a B, give it a new C, then give the B to a new A.