PDF 82K

Transcription

PDF 82K
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
Ausarbeitung des Artikels von Martin Fowler
Inversion of Control Containers and
the Dependency Injection pattern
http://martinfowler.com/articles/injection.html
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
Inhaltsverzeichnis
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
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
1. Martin Fowler
Martin Fowler ist Autor und renommierter Referent zum
Thema Softwarearchitektur, spezialisiert auf objektorientierte Analyse und Design, UML, Entwurfsmuster und
agile Softwareentwicklung.
Er schrieb fünf bedeutende
Softwareentwicklung.
Bücher
zum
Thema
Heute arbeitet er als Chefentwickler beim ConsultingUnternehmen ThoughtWorks.
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
2. Einleitung
Das generelle Problem ist die Art der Zusammenführung unterschiedlicher
Elemente.
Beispiel:
class MovieLister...
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()]);
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
2. Einleitung
Beispiel: MovieLister
public interface MovieFinder {
List findAll();
}
class MovieLister...
private MovieFinder finder;
public MovieLister() {
finder = new
ColonDelimitedMovieFinder("movies1.txt");
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3. IoC / Dependency Injection
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.
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.1 Constructor Injection
Am Beispiel: PicoContainer
(Komponenten definieren)
class MovieLister...
public MovieLister(MovieFinder finder){
this.finder = finder;
}
class ColonMovieFinder...
public ColonMovieFinder(String filename) {
this.filename = filename;
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.1 Constructor Injection
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;
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.1 Constructor Injection
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());
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.2 Setter Injection
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;
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.2 Setter Injection
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>
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.2 Setter Injection
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());
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
3.3 Interface Injection
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
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
4. Service Locator
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;
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
4. Service Locator
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());
}
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
4.1 Nutzung eines abgetrennten Interfaces
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 komplette
ServiceLocator Schnittstelle zu nutzen.
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
4.2 Dynamischer Service Locator
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 ServiceLocator
erstellen, der einem erlaubt jeden Dienst, den man benötigen könnte, zu integrieren und
wä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.
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
4.3 Nutzung von Locator und Injection
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.
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
5. Service Locator vs Dependency Injection
- 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)
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
6. Constructor vs Setter Injection
- 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
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler
IoC Containers and the Dependency Injection pattern
University of Applied Sciences
7. Fazit
Beim entwicklen von Anwendungsklassen sind Service Locator und Dependency
Injection 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 gewissen
Problemen kommt.
11.12.2006 | Komponentenbasierte Softwareentwicklung | Dependency Injection | André Kley, Julian Päuler

Documents pareils