DEV Community

Cover image for Decoding DI vs. DI ✨
Peter B. Youssef
Peter B. Youssef

Posted on

Decoding DI vs. DI ✨

Dependency Injection (DI) vs. Dependency Inversion (DI)

Dependency Injection (DI):
Dependency Injection is a technique where external dependencies are passed to a class rather than the class creating them itself. It's about injecting dependencies from the outside. In other words, instead of a class creating its own dependencies, those dependencies are provided from the outside.

Example of Dependency Injection:
Consider a Laravel controller that requires a service to handle business logic. Without DI, the controller would create the service instance internally. With DI, the service instance is passed to the controller's constructor.

// Without Dependency Injection
class UserController extends Controller
{
    public function index()
    {
        $userService = new UserService();
        $users = $userService->getAllUsers();
        return view('users.index', ['users' => $users]);
    }
}

// With Dependency Injection
class UserController extends Controller
{
    protected $userService;

    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function index()
    {
        $users = $this->userService->getAllUsers();
        return view('users.index', ['users' => $users]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Dependency Inversion (DI):
Dependency Inversion is a principle from the SOLID design principles. It suggests that high-level modules should not depend on low-level modules. Both should depend on abstractions. Additionally, abstractions should not depend on details; details should depend on abstractions. This means that instead of tightly coupling components, they should depend on abstractions (interfaces or abstract classes).

Example of Dependency Inversion:
Suppose you have a Laravel controller that interacts with a specific repository implementation. Without applying DI, the controller would directly depend on that implementation. With DI and DI principle, you would use an interface as an abstraction for the repository, and then inject the concrete implementation.

// Without Dependency Inversion
class UserController extends Controller
{
    protected $userRepository;

    public function __construct()
    {
        $this->userRepository = new UserRepository();
    }

    public function index()
    {
        $users = $this->userRepository->getAll();
        return view('users.index', ['users' => $users]);
    }
}

// With Dependency Inversion
interface UserRepositoryInterface
{
    public function getAll();
}

class UserRepository implements UserRepositoryInterface
{
    public function getAll()
    {
        // Fetch users from database
    }
}

class UserController extends Controller
{
    protected $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function index()
    {
        $users = $this->userRepository->getAll();
        return view('users.index', ['users' => $users]);
    }
}
Enter fullscreen mode Exit fullscreen mode

In the Dependency Injection example, you see how the UserService is injected into the controller's constructor.
In the Dependency Inversion example, the UserRepositoryInterface is used to define the contract, and the UserController depends on this abstraction instead of a concrete implementation.

Top comments (0)