Loose Coupling with Interfaces and Dependency Injection
Loose coupling means a component depends on abstractions rather than concrete implementations. Interfaces provide the abstraction boundary, while dependency injection supplies the required implementation from outside the dependent class. This makes the component easier to test, replace and evolve. Constructor injection is generally my preferred approach because required dependencies are explicit and the object cannot be constructed without them.
Depend on an interface rather than a concrete class.
Inject dependencies instead of constructing them internally.
Constructor injection makes required dependencies explicit.
Implementations can be replaced without changing the consumer.
Testing becomes easier because mocks, stubs or fakes can implement the interface.
Dependency injection is a design technique; a DI framework is optional.