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.
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.
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.
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