Infusion addiction

I read about Dependency Injection, but the examples I found look like bad code to me, so my main question is, do I correctly believe this is bad code, or do I not understand its purpose and is my example better?

class Photo {
   protected $db;
   public function __construct()
   {
      $this->db = DB::getInstance();
   }
}

      

So this is bad code, and the suggestion of Dependency Injection because of the many customizations that can be created if we explicitly set each variable is:

class Container {
   protected $db;
   public static newPhoto()
   {
      $photo = new Photo;
      $photo->setDB(static::$db);
      $photo->setConfig();
      $photo->setResponse();
      return $photo;
   }
}
$photo = Container::newPhoto();

      

But correct me if I'm wrong, we just created a class whose sole responsibility is to create another class seems completely pointless and we are using static methods which seem to be very bad.

One advantage I see, which surprisingly to me is not mentioned, is that we can now independently test the Photo class using the settings, while in the first example we could not.

Something like this makes more sense to me:

class Photo {
   protected $db;
   protected $config;
   protected $response;
   public function __construct($dbConn=null,$config='123',$response=true)
   {
      if(is_null($dbConn))
          $this->db = DB::getInstance();
      else
          $this->db = $dbConn;
      ...etc
   }
}
$photo = new Photo($dbConn);

      

The class builds itself, there is no need for the static method to actually be called, the class can be checked with dummy data if the values ​​are used differently when it reverts to default values ​​(which seems to be the only point of the Container class), and the dependencies are still somewhat obvious in contrast to the container.

+3


source to share


2 answers


I don't know where you relied on DI, but the resources seem pretty dubious. Instead, you should start by watching this lecture , followed by an article by Martin Fowler. This short video may have been added .

class Container {
   protected $db;
   public static newPhoto()
   {
      $photo = new Photo;
      $photo->setDB(static::$db);
      $photo->setConfig();
      $photo->setResponse();
      return $photo;
   }
}
$photo = Container::newPhoto();

      

This is not dependency injection. In fact, this is just an example of a poorly implemented static factory method pattern (anti). Especially the magical methods $photo->setConfig()

and $photo->setResponse()

, which seem to do some work, but don't receive any parameters.

And here's this code:

class Photo {
   protected $db;
   protected $config;
   protected $response;
   public function __construct($dbConn=null,$config='123',$response=true)
   {
      if(is_null($dbConn))
          $this->db = DB::getInstance();
      else
          $this->db = $dbConn;
      ...etc
   }
}
$photo = new Photo($dbConn);

      



Instead of just assigning values, you decide to hide its dependencies and, if not provided, take them from the global scope. And of course your constructor ends up containing enough computation log. Thus, make it impractical.

Oh .. and then there is a magic boolean value. Whenever such a parameter is assigned to a class in the constructor, it is a clear sign that you really need two different classes that implement the same interface.

So, to answer your question:

I read about Dependency Injection, but the examples I found look like bad code to me, so my main question is, do I correctly believe this is bad code, or do I not understand its purpose and is my example better?

Not. Your example is no better. You have just combined the worst parts from your previous code example into a single class definition.

+1


source


The purpose of the Dependency Injection pattern is to share how objects that work together are built. In your example, it is not a problem for the Photo class to know how to build a DB instance, but only to use the DB instance to achieve its goals.

The obvious benefit you've already noticed is testing, where you can easily pass in a DB instance if you only want to test the Photo functionality. But you can also think about connection pooling, for example if the container has a pool of DB instances and pass one of them to your Photo object to do its work. When the photo's lifecycle ends, the DB instance is returned to the pool and used elsewhere.



Implementation of this pattern can be achieved using constructors with arguments, setters, annotations (in Java at least), and even XML configuration files. In the case of annotations or XML configuration files, the container will parse this information, create the appropriate required objects, and inject them into the client class.

What you describe in C1 and C2 is a factory class that provides static methods for getting Photo instances. This is a very common pattern used in many places in Java.

+2


source







All Articles