OO Design muss mit Objekten umgehen, die sich gegenseitig beeinflussen. Dadurch enstehen zwangsläufig Abhängigkeiten zwischen den Objekten. Diese sind potentiell Grund für Seiteneffekte.
Deshalb sollten die Abhängigkeiten möglichst reduziert werden.
Kopplungen & Abhängigkeiten
Ein Beispiel für eine enge Kopplung zwischen zwei Objekten:
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
Ein Tax Objekt ist direkt gekoppelt an die Personen Klasse.
Die Steuerberechnung funktioniert in dieser naiven Implementierung also nur für Personen:
taxation = Taxation.new 5_000
taxation.debit(20)
# => 1000
Allerdings sollten auch andere Objekte (Firmen oder generell Rechtsformen) besteuert werden können.
Dependency Injection
Die nötige Flexibilität kann in solchen Situationen mit Dependency Injection erreicht werden. Dabei wird das benötigte Objekt (Person, Company etc.) nicht direkt in der Klasse (Tax) instantiiert, sondern außerhalb und stattdessen lediglich übergeben:
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
Die Abhängigkeit wurde in das Tax Objekt injiziert.
Die Steuerberechnung funktioniert nun mit allen Objekten, die das erwartete Interface (income) implementiert haben:
taxation = Taxation.new Person.new(5_000)
taxation.debit(20)
# => 1000
Dadurch gibt es keine Kopplung zwischen den Klassen mehr, sondern lediglich zwischen den Interfaces.
Flexibilität
Die erhöhte Flexibilität läßt sich einfach umsetzen und macht sich bezahlt, weil sich die Funktionalität mit Dependency Injection leicht erweitern läßt:
taxation = Taxation.new Company.new(100_000)
taxation.debit(20)
# => 20000