Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
bin gerade dabei mich in Guice einzuarbeiten. Und bisher fand ich das alles sehr schick und einleuchtend. Aber jetzt bin ich an einem Punkt, wo ich mal einen guten Ratschlag von euch brauche.
Ich habe eine Klasse A, die in einer Methode Objekte der Klasse B erzeugt. Dafür bekommt die Klasse A im Konstruktur eine Factory für Klasse B injiziert. Diese Factory hat eine newInstance()-Methode mit Rückgabetyp der Klasse B. Um jetzt neue Objekte der Klasse B erzeugen zu können, die auch mit Konstruktor-Injection arbeitet, müsste ich blöderweise den Injector von Guice mit übergeben, um dann
Java:
injector.getInstance(KlasseB.class);
aufrufen zu können... aber das kann ja nicht die Lösung sein, oder etwa doch?
Klasse A und B implementieren jeweils Interface A bzw. B. Auch die Factory implementiert das Interface Factory für Klasse B. Ich hatte eigentlich gehofft, mein Problem mit der Factory zu lösen. Aber dadurch habe ich es nur in die Factory verschoben.
Was ich mir noch vorstellen könnte, in Klasse B mit Setter Injection zu arbeiten. Dann müsste Guice mit Auto Binding arbeiten. Was aber auch wieder nicht geht, da ich das Interface B schlecht instanzieren kann. ???:L
Ich bin verwirrt. Vielleicht ist es auch nur zu spät und ich sehe morgen klarer. :gaen:
Ich benutze AssistedInjection an einer Stelle: Eigentlich will ich mein Hauptfenster injizieren lassen, es muss aber einen Nutzernamen übergeben bekommen. Deshalb injiziere ich stattdessen eine Factory:
Java:
public class MyApp {
@Inject
private MyApp(MainFrameFactory mainFrameFactory) {
String userName = loginAndAuthenticate();
MainFrame mainFrame = mainFrameFactory.create(userName);
}
public static void main(String[] args) {
final Injector injector = Guice.createInjector(new SomeModule());
injector.getInstance(MyApp.class);
}
}
Die Factory muss ich nicht implementieren, ein Interface reicht, den Rest bastelt Guice:
Java:
public interface MainFrameFactory {
MainFrame create(String userName);
}
Das MainFrame wird mit dem "assistiert" übergebenen Nutzernamen und ganz normal injizierten Parametern konstruiert:
Java:
public class MainFrame {
@Inject
public MainFrame(@Assisted String userName,
UserManager userManager,
Set<WorktimePanel> panels) {
}
...
}
Die Bindung im Modul sieht so aus:
Java:
public class SomeModule {
protected void configure() {
bind(MainFrameFactory.class).toProvider(
FactoryProvider.newFactory(MainFrameFactory.class, MainFrame.class));
//und die anderen Sachen, die MainFrame braucht
}
}
Danke euch beiden. AssistedInjection hat mein Problem gelöst. Hatte die FAQ-Seite dazu gestern sogar schon aufgehabt, aber sie nur überflogen.
Ein wenig merkwürdig kommt mir die Lösung aber dennoch vor, da ich dadurch an einer Stelle eine Factory in einer Factory habe, bedingt durch das automatische Erzeugen der ProviderFactory von Guice. Wäre gut nochmal zu hören, was ihr davon haltet (CellGridFactory und CellGridProviderFactory).
Damit das nicht zu trocken wird, poste ich den Code dazu.
Es handelt sich um eine GameOfLife-Implementierung. Mein persönliches HelloWorld, um mit neuen Frameworks vertrauter zu werden. Das Problem ist mir gestern bei folgender Methode aufgefallen:
Java:
public class GameOfLifeImpl implements GameOfLife {
...
@Override
public void next() {
CellGrid nextGeneration = cellGridFactory.newInstance(cellGrid);
computeNextGenerationCellGrid(nextGeneration);
setCellGrid(nextGeneration);
incrementGeneration();
}
...
}
Die Factory musste anhand des übergebenen CellGrids (also dessen Breite, Höhe etc pp) eine neue CellGrid-Instanz erzeugen. Des Weiteren bietet diese Factory noch Methoden, um CellGrids zu erstellen, die zufällig mit Zellen befüllt sind.
Java:
public interface CellGridFactory {
CellGrid newInstance(CellGrid cellGrid);
CellGrid newInstance(int width, int height, boolean isTorus);
CellGrid newInstanceFilledRandomlyWithCells(CellGrid cellGrid);
CellGrid newInstanceFilledRandomlyWithCells(int width, int height, boolean isTorus);
}
Ich habe das Problem jetzt wie folgt gelöst: Die Klasse CellGridImpl hat drei AssistedInject-Parameter im Konstruktor (width, height, isTorus). Dabei mussten width und height als NamedAssisted annotiert werden, da sie den gleichen Typ haben und Guice ohne die Namen keine Zuweisung machen kann. Dann gibt es eine "DummyFactory", die ich CellGridProviderFactory genannt habe. Das ist die von Guice automatisch erzeugte Factory. Diese wird der eigentlichen CellGridFactory im Konstruktor injiziert. Es ist halt nur schade, dass Guice bei der erzeugten Factory lediglich diese create-Methode zulässt und man nicht selbst noch eigene Factory-Methoden implementieren kann. Deswegen dieser kleine Umweg über die CellGridFactory mit injizierter CellGridProviderFactory.
Natürlich könnte man argumentieren, dass das zufällige Befüllen mit Zellen, in die Klasse CellGridImpl verschoben werden könnte oder in eine Helper-Klasse als statische Methode. Aber dieses Projekt ist ein bereits implementiertes und ich wollte versuchen, die Struktur möglichst beizubehalten - mit Guice nur die Bindings vornehmen. Außerdem finde ich, passt das zufällige Befüllen mit Zellen sehr gut in eine Factory und man erspart sich unnötige statische Helfermethoden.
CellGridImpl mit benannten Assisted-Parameter:
Java:
public class CellGridImpl implements CellGrid {
private int width;
private int height;
private boolean isTorus;
...
@Inject
public CellGridImpl(@Assisted("width") int width, @Assisted("height") int height,
@Assisted boolean isTorus) {
checkArgument(width > 0, "width must be greater than 0");
checkArgument(height > 0, "height must be greater than 0");
this.width = width;
this.height = height;
this.isTorus = isTorus;
...
}
...
}
Die eigentliche CellGridFactory-Implementierung:
Java:
public class CellGridFactoryImpl implements CellGridFactory {
private CellGridProviderFactory cellGridProviderFactory;
@Inject
public CellGridFactoryImpl(CellGridProviderFactory cellGridProviderFactory) {
checkNotNull(cellGridProviderFactory);
this.cellGridProviderFactory = cellGridProviderFactory;
}
...
@Override
public CellGrid newInstance(int width, int height, boolean isTorus) {
checkArgument(width > 0, "width must be greater than 0");
checkArgument(height > 0, "height must be greater than 0");
return cellGridProviderFactory.create(width, height, isTorus);
}
...
@Override
public CellGrid newInstanceFilledRandomlyWithCells(int width, int height,
boolean isTorus) {
CellGrid newCellGrid = newInstance(width, height, isTorus);
fillRandomlyWithCells(newCellGrid);
return newCellGrid;
}
...
}
Das Interface für die DummyFactory, welches Guice benötigt, um mit den Assisted-Annotations arbeiten zu können (Wichtig: Auch hier muss man mit den gleichen benannten Assisted Parametern arbeiten wie bei CellGridImpl):
Java:
public interface CellGridProviderFactory {
CellGrid create(@Assisted("width") int width, @Assisted("height") int height, boolean isTorus);
}
Der provisorische Startpunkt, um zu testen, ob Guice die Konfiguration schluckt: