Inversion of Control Containers and the Dependency ... · IoC Containers and the Dependency...
Transcript of Inversion of Control Containers and the Dependency ... · IoC Containers and the Dependency...
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
Ausarbeitung des Artikels von Martin Fowler
Inversion of Control Containers and
the Dependency Injection pattern
http://martinfowler.com/articles/injection.html
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
Inhaltsverzeichnis
IoC Containers and the Dependency Injection pattern
1. Martin Fowler 5. Service Locator vs Dependency Injection
2. Einleitung 6. Constructor vs Setter Injection
3. IoC / Dependency Injection 7. Fazit
3.1 Constructor Injection
3.2 Setter Injection
3.3 Interface Injection
4. Service Locator
4.1 Nutzung eines abgetrennten Interfaces
4.2 Dynamischer Service Locator
4.3 Nutzung von Locator und Injection
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
1. Martin Fowler
IoC Containers and the Dependency Injection pattern
Martin Fowler ist Autor und renommierter Referent zum Thema Softwarearchitektur, spezialisiert auf objekt-orientierte Analyse und Design, UML, Entwurfsmuster und agile Softwareentwicklung.
Er schrieb fünf bedeutende Bücher zum Thema Softwareentwicklung.
Heute arbeitet er als Chefentwickler beim Consulting-Unternehmen ThoughtWorks.
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
2. Einleitung
IoC Containers and the Dependency Injection pattern
Das generelle Problem ist die Art der Zusammenführung unterschiedlicher Elemente.
class MovieLister...
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(newMovie[allMovies.size()]);
}
Beispiel:
MovieLister
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
2. Einleitung
IoC Containers and the Dependency Injection pattern
Beispiel: MovieLister
public interface MovieFinder {
List findAll();
}
class MovieLister...
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3. IoC / Dependency Injection
IoC Containers and the Dependency Injection pattern
Im vorherigen Beispiel hat der „lister“ die „finder“ Implementation durch direktes Ansprechen gefunden.
Dies unterscheidet den „finder“ vom Plugin.
Durch ein separates Assemblermodul soll die Implementation in den „lister“eingebunden werden.
Als Resultat vieler Diskussionen mit IoC Vertretern hat man sich auf den Namen „Dependency Injection” (Unabhängige Injizierung) geeinigt, da der Name IoC viel zu allgemein gehalten ist.
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.1 Constructor Injection
IoC Containers and the Dependency Injection pattern
Am Beispiel: PicoContainer(Komponenten definieren)
class MovieLister...
public MovieLister(MovieFinder finder){
this.finder = finder;
}
class ColonMovieFinder...
public ColonMovieFinder(String filename) {
this.filename = filename;
}
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.1 Constructor Injection
IoC Containers and the Dependency Injection pattern
Am Beispiel: PicoContainer (Konfigurieren)
private MutablePicoContainer configureContainer() {
//Erzeugung eines Pico Containers
MutablePicoContainer pico = new DefaultPicoContainer();
Parameter[] finderParams =
{new ConstantParameter ("movies1.txt")};
pico.registerComponentImplementation (MovieFinder.class, ColonMovieFinder.class, finderParams);
Registriert eine Klasse(2) unter einem bestimmten Key(1), Der Parameter(3) wird dann mit zum
Konstruktor übergeben (später)
pico.registerComponentImplementation(MovieLister.class);
Registriert eine Klasse(1) bei der von Bedarf ein Objekt erzeugt wird, mit sich selbst(1) als Key
return pico;
}
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.1 Constructor Injection
IoC Containers and the Dependency Injection pattern
Am Beispiel: PicoContainer (Testen)
public void testWithPico() {
MutablePicoContainer pico = configureContainer(); siehe oben
MovieLister lister = (MovieLister) pico.getComponentInstance(MovieLister.class);
Holt sich eine Componente die unter diesem Schlüssel reg. wurde
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.2 Setter Injection
IoC Containers and the Dependency Injection pattern
Am Beispiel: Spring (Komponenten definieren)
class MovieLister...
private MovieFinder finder;
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
class ColonMovieFinder...
public void setFilename(String filename) {
this.filename = filename;
}
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.2 Setter Injection
IoC Containers and the Dependency Injection pattern
Am Beispiel: Spring (Konfigurieren)
<beans>
<bean id="MovieLister" class="spring.MovieLister">
<property name="finder">
<ref local="MovieFinder"/>
</property>
</bean>
<bean id="MovieFinder" class="spring.ColonMovieFinder">
<property name="filename">
<value>movies1.txt</value>
</property>
</bean>
</beans>
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.2 Setter Injection
IoC Containers and the Dependency Injection pattern
Am Beispiel: Spring (Testen)
public void testWithSpring() throws Exception {
ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
MovieLister lister = (MovieLister) ctx.getBean("MovieLister");
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
3.3 Interface Injection
IoC Containers and the Dependency Injection pattern
Für alle set-Methoden (Setter-Injection) werden eigene Interfaces definiert.
Diese enthalten die Inject-Methoden:
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
class MovieLister implements InjectFinder{
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
}
Konfiguration hat zwei Ebenen: Die Registrierung der Komponenten
Die Registrierung der Injektoren
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
4. Service Locator
IoC Containers and the Dependency Injection pattern
Die Grundidee hinter einem Service Locator besteht in einem Objekt, dass alle Dienste beschafft, die die Applikation benötigen könnte.
class MovieLister...MovieFinder finder = ServiceLocator.movieFinder();
class ServiceLocator...public static MovieFinder movieFinder() {
return soleInstance.movieFinder; } public static void load(ServiceLocator arg) {
soleInstance = arg; }public ServiceLocator(MovieFinder movieFinder) {
this.movieFinder = movieFinder;}
private static ServiceLocator soleInstance; private MovieFinder movieFinder;
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
4. Service Locator
IoC Containers and the Dependency Injection pattern
Konfiguration und Test
class Tester... private void configure() {
ServiceLocator.load(new ServiceLocator(new ColonMovieFinder("movies1.txt"))); }
public void testSimple() { configure(); MovieLister lister = new MovieLister(); Movie[] movies = lister.moviesDirectedBy("Sergio Leone"); assertEquals("Once Upon a Time in the West",
movies[0].getTitle()); }
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
4.1 Nutzung eines abgetrennten Interfaces
IoC Containers and the Dependency Injection pattern
Eins der Probleme des einfachen Ansatzes ist, dass der MovieLister abhängig von der kompletten ServiceLocator Klasse ist, obwohl er nur einen einzigen Dienst nutzt.
Man kann dieses Problem reduzieren, indem man ein Interface zwischen dem MovieLister und dem Service Locator schiebt.
Somit kann der lister nur einen Teil der Schnittstelle ansprechen, ohne die kompletteServiceLocator Schnittstelle zu nutzen.
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
4.2 Dynamischer Service Locator
IoC Containers and the Dependency Injection pattern
Das vorherige Beispiel war statisch, da die ServiceLocator Klasse Methoden für jeden Dienst besaß, den sie benötigte.
Das ist aber nicht der einzige Weg. Man kann auch einen dynamischen ServiceLocatorerstellen, der einem erlaubt jeden Dienst, den man benötigen könnte, zu integrieren undwährend der Laufzeit auszuwählen.
Dazu benutzt der ServiceLocator eine HashMap, die die Services enthält. Sie bietet generische Methoden zum Erhalten und Laden der Dienste an.
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
4.3 Nutzung von Locator und Injection
IoC Containers and the Dependency Injection pattern
Dependency Injection und Service Locator sind keine sich gegenseitig ausschließende Konzepte.
Beispiel:
public class MyMovieLister implements MovieLister, Serviceable { private MovieFinder finder;public void service(ServiceManager manager) {
finder = (MovieFinder)manager.lookup("finder");}
}
Die Service Methode ist ein Beispiel für Interface Injection, die dem Kontainer erlaubt einen ServiceManager in MyMovieLister zu injezieren.
Der ServiceManager ist ein Beispiel für einen Service Locator. Hier speichert der Lister den Manager nicht in einem Feld, stattdessen benutzt er ihn um den finder direkt zu speichern.
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
5. Service Locator vs Dependency Injection
IoC Containers and the Dependency Injection pattern
- Beide Implementationen stellen das fundamentale Entkoppeln bereit,- Bei beiden ist der Applikations Code unabhängig von der konkreten Implementation
des Service interfaces.
Service Locator:- die Applikations Klasse fragt explizit den Locator- jeder Nutzer ist Abhängig vom Locator- um die Abhängigkeiten zu sehen, muss man den Code durchsuchen
Dependency Injection:- ss gibt keine explizite Anfrage, der Service erscheint in der Applikations Klasse
durch Inversion of Control- schwieriger zu debuggen- man sieht die Abhängigkeiten einfacher (Im Konstrukor oder bei den Set-Methoden)
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
6. Constructor vs Setter Injection
IoC Containers and the Dependency Injection pattern
- Beide können sehr einfach Verbindungen zwischen Komponenten herstellen
Constructor:- jedes Objekt ist sofort verfügbar- geringfügig weniger Code - unveränderbare Felder können versteckt werden
Setter:- keine langen Argumentenlisten die unübersichtlich werden könnten - Setter bekommen eindeutige Namen - Konstruktoren werden nicht automatisch vererbt
University of Applied Sciences
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
7. Fazit
IoC Containers and the Dependency Injection pattern
Beim entwicklen von Anwendungsklassen sind Service Locator und DependencyInjection fast gleich. M.F. empfiehlt den Service Locator zu nutzen.
Es sei denn man entwickelt mehrere Klassen die in verschiedene Anwendungen laufen sollen.
Nutzt man Dependency Injection empfiehlt es sich mit der Constructor-Injection zu starten. Man sollte aber bereit sein auf Setter- Injection umzustellen, falls es zu gewissenProblemen kommt.