Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Many dependencies in service

I have trouble with dependencies in my application in service layer.

I have following class:

   <?php

class UserService{

    private $userRepository;
    private $vocationService;
    private $roleService;

    public function __construct(UserRepository $userRepository, VocationService $vocationService, RoleService $roleService)
    {
        $this->userRepository = $userRepository;
        $this->vocationService = $vocationService;
        $this->roleService = $roleService;
    }


} 

There are only three dependencies which I'm injecting. Assume, I want to add next dependency, for example: NextService. My constructor will grow again.

What if I wanted to pass more dependencies within constructor ?

Maybe should I solve this problem by passing IoC container and then get desirable class? Here is an example:

<?php

class UserService{

    private $userRepository;
    private $vocationService;
    private $roleService;

    public function __construct(ContainerInterface $container)
    {
        $this->userRepository = $container->get('userRepo');
        $this->vocationService = $container->get('vocService');
        $this->roleService = $container->get('roleService');
    }

} 

But now my UserService class depends on IoC container which I'm injecting.

How to solve a problem following good practices?

Regards, Adam

like image 886
ajtamwojtek Avatar asked Dec 19 '22 09:12

ajtamwojtek


2 Answers

Injecting the container as a dependency to your service is considered as a bad practice for multiple reasons. I think the main point here is to figure out why and then try to understand the problem that leads you to think about "injecting the container" as a possible solution and how to solve this problem.

In object oriented programming, it's important to clearly define the relations between objects. When you're looking at a given object dependencies, it should be intuitive to understand how the object behaves and what are the other objects it relies on by looking at its public API.

It's also a bad idea to let your object rely on a dependency resolver, In the example you shared your object can't live without the container which is provided by the DI component. If you want to use that object elsewhere, in an application that uses another framework for example, you'll then have to rethink the way your object get its dependencies and refactor it.

The main problem here is to understand why your service needs all these dependencies,

In object-oriented programming, the single responsibility principle states that every context (class, function, variable, etc.) should define a single responsibility, and that responsibility should be entirely encapsulated by the context. All its services should be narrowly aligned with that responsibility. Source: Wikipedia

Based on this definition, I think you should split your UserService into services that handle only one responsability each.

  • A service that fetch users and save them to your dababase for example
  • Another service that manages roles for example
  • ... and so on
like image 110
Ahmed Siouani Avatar answered Jan 01 '23 23:01

Ahmed Siouani


I agree that __construct can grow fairly easy.

However, you have a Setter DI at your disposal: http://symfony.com/doc/current/components/dependency_injection/types.html#setter-injection

Morover, there is a Property DI, but I wouldn't recommed it as ti leaves your service wide-open to manipulation: http://symfony.com/doc/current/components/dependency_injection/types.html#property-injection

like image 28
Jovan Perovic Avatar answered Jan 02 '23 00:01

Jovan Perovic