Lassen Sie uns ein fiktives Beispiel erstellen.
Klasse A
in Paket packageA
:
package packageA;
import packageB.B;
public class A {
B myB;
public A() {
this.myB = new B();
}
public void doSomethingThatUsesB() {
System.out.println("Doing things with myB");
this.myB.doSomething();
}
}
Klasse B
in Paket packageB
:
package packageB;
public class B {
public void doSomething() {
System.out.println("B did something.");
}
}
Wie Sie sehen, hängt A
auf B
. Ohne B
kann A
nicht verwendet werden. Aber was, wenn wir in Zukunft B
durch eine BetterB
ersetzen wollen? Nun starten wir eine Schnittstelle Inter
innerhalb packageA
zu erstellen:
package packageA;
public interface Inter {
public void doSomething();
}
diese Schnittstelle zu nutzen, wir import packageA.Inter;
und lassen B implements Inter
in B
und ersetzen alle Vorkommen von B
innerhalb A
mit Inter
. Das Ergebnis ist diese modifizierte Version von A
:
package packageA;
public class A {
Inter myInter;
public A() {
this.myInter = ???; // What to do here?
}
public void doSomethingThatUsesInter() {
System.out.println("Doing things with myInter");
this.myInter.doSomething();
}
}
An dieser Stelle sehen wir bereits, dass die Abhängigkeit A
-B
gegangen ist: die import packageB.B;
nicht mehr benötigt wird. Es gibt nur ein Problem: Wir können keine Instanz einer Schnittstelle instanziieren. Aber Inversion of control kommt zur Rettung. Anstatt etwas vom Typ Inter
wihtin A
‚s Konstruktor instanziiert wird, werden wir etwas, das implements Inter
als Parameter für den Konstruktor fordern:
package packageA;
public class A {
Inter myInter;
public A(Inter myInter) {
this.myInter = myInter;
}
public void doSomethingThatUsesInter() {
System.out.println("Doing things with myInter");
this.myInter.doSomething();
}
}
Mit diesem Ansatz, den wir nun die konkrete Umsetzung von Inter
innerhalb A
nach Belieben ändern können. Angenommen, Sie eine neue Klasse BetterB
schreiben:
package packageB;
import packageA.Inter;
public class BetterB implements Inter {
@Override
public void doSomething() {
System.out.println("BetterB did something.");
}
}
Jetzt können wir instantiante A
s mit verschiedenen Inter
Implementierungen innerhalb A
Inter b = new B();
A aWithB = new A(b);
aWithB.doSomethingThatUsesInter();
Inter betterB = new BetterB();
A aWithBetterB = new A(betterB);
aWithBetterB.doSomethingThatUsesInter();
Und wir haben nichts zu ändern. Der Code ist jetzt entkoppelt und Sie können die konkrete Implementierung von Inter
beliebig ändern, solange der/die Vertrag (e) von Inter
erfüllt ist (sind). Vor allem können Sie Code unterstützen, der zukünftig generiert wird und Inter
implementiert.
Ich empfehle Robert C. Martin Veröffentlichungen über SOLID Regeln der objektorientierten Programmierung. Hier einige Details zu Ihrem Problem: http://www.objectoror.com/resources/articles/dip.pdf –