0

I know that we usually inject the dependencies by instantiating them in the constructor of the class we are injecting to. However, in my own experience, I just pass the class of the dependency as a parameter and do not instantiate in the constructor like the code below(I am currently working in Ruby):

class A
  def initialize(dependency: AnotherClass)
    @dependency = dependency
  end
  
  def main_operation
    # do something here
    @params = # do some stuff to get some params here
    result = some_operation_to_perform_on_the_dependency_class
    # do something with result then return
  end

  private

  attr_reader :dependency
  
  def some_operation_to_perform_on_the_dependency_class
    denpendency.new(@params).do_some_operation
  end
end

My point is it doesn't make sense to instantiate the dependency object in the constructor because I need to pass in params which I can't get at the beginning

Therefore, I would love to hear are there any better ways/practices to do this(in OOP general or specifically in Ruby)? Or this is the only way to do it?

6
  • Does this answer your question? Legitimate "real work" in a constructor?
    – gnat
    Commented Jun 6, 2021 at 14:47
  • @gnat: I am not sure you understood the question - to be honest, I am pretty sure you did not.
    – Doc Brown
    Commented Jun 6, 2021 at 17:31
  • "it doesn't make sense to instantiate the dependency object in the constructor" - but that's not what's usually done in dependency injection; usually, the dependency is instantiated by some 3rd piece of code, outside of the class, and the object is passed in as a parameter. I'm not a Ruby-ist, but if I read your code correctly, it seems like you're storing the type of the dependency (ignoring the actual parameter completely), and than instantiating that type later on. But, unless I'm mistaken, that won't allow you to pass in an instance of a subtype, while passing/storing an object will. Commented Jun 6, 2021 at 20:37
  • I just realized dependency: AnotherClass might just be a default parameter. But shouldn't it then be @dependency = dependency? In any case, passing in a class is actually a similar process and the same overall idea, just a slightly different design - it's like passing in a factory that can create the instance for you at a later time. It's a known approach, that in other languages might manifest as say, passing in a lambda. The injected class is the factory; it's essentially an object that exists outside of your class, that you then pass in. Commented Jun 6, 2021 at 20:47
  • @gnat Thanks for your suggestion, but actually it doesn't help, but I found a great answer below
    – Fatima
    Commented Jun 7, 2021 at 5:18

2 Answers 2

6

It is not very sensible to ask what one does "usually" - how to design this kind of injection should depend on the requirements within the system, not on some habit of the programmer.

When a certain dependency A can be created before the construction of a dependend object of type B, injecting an A-object through the constructor of B is often the most simple solution and hence preferable. If that's not possible, because, as you wrote by yourself, the construction of the dependency can only be done at a later point in time, one needs to implement a more complex solution. In strictly typed languages like Java, C# or C++, the idiomatic solution would be to inject an abstract factory object, so the factory can be used to create the required dependency when possible. A simplified variant of this pattern, which is often sufficient for many purposes, is to provide this factory in form of a "call back" (delegate, higher-order function, whatever it is called in the specific environment).

In a language with dynamic typing like Ruby, injecting the class type instead of an object is a functionally equivalent approach, as you demonstrated it, with the advantage of being very concise. So in case this approach is sufficient for your case, go ahead, there is no need to overthink it. If the approach demonstrates itself not to be sufficient any more (for example, because the construction process itself requires more dependencies), then will be the time for thinking about a different solution like a factory.

1

First let's get the terminology right.

we usually inject the dependencies by instantiating them in the constructor of the class we are injecting to

This is nonsense. You either inject, in which case the dependency object pre-exists, OR you create, in which case it is not injected because it does not exist yet.

The choice boils down to the scope of the dependency object.

  • If it is only meaningful within the instance of the class, make the class create it and let it own it as one of its private members. This makes for nice encapsulation, it keeps the noise inside.
  • If the object is meaningful in its own right and/or other classes may depend on it as well, keep it external to the class and inject it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.