Dependency Injection pattern

OO design has to deal with objects interacting with each other. The resulting dependencies between those objects are potential reasons for side effects.
Therefore, the dependencies should be reduced as much as possible.

Coupled dependencies

An example for a tight coupling between two objects:

class Taxation
  attr_reader :person

  def initialize(income)
    @person = Person.new(income)
  end

  def debit(vat_in_percent)
    person.income.to_d * vat_in_percent.to_d / 100.to_d
  end
end

A Tax object is directly coupled with the Person class.
The tax calculation only works for people in this naive implementation:

taxation = Taxation.new 5_000
taxation.debit(20)
# => 1000

However, other objects (companies or generally legal forms) should also be taxable.

Dependency Injection

In such situations the necessary flexibility can be achieved with Dependency Injection. In this case, the required object (Person, Company, etc.) is not instantiated directly in the class (Tax) any longer. But it is created outside and passed instead:

class Taxation
  attr_reader :legal_form

  def initialize(legal_form)
    @legal_form = legal_form
  end

  def debit(vat)
    legal_form.income.to_d * vat_in_percent.to_d / 100.to_d
  end
end

The dependency was injected into the Tax object.
The tax calculation works with all objects that have implemented the expected interface (income):

taxation = Taxation.new Person.new(5_000)
taxation.debit(20)
# => 1000

Through Dependecy Injection there is no coupling between the classes, but only between the interfaces.

Flexibility

The resulting flexibility through Dependency Injection is introduced quite easily and it pays off whenever the functionality has to be extended:

taxation = Taxation.new Company.new(100_000)
taxation.debit(20)
# => 20000