+ Antworten
Ergebnis 1 bis 12 von 12

Thema: Guice: Zwei Probleme

  1. #1
    User short Themenstarter
    Avatar von TheChemist
    Registriert seit
    07.08.2013
    Fachbeiträge
    25
    Genannt
    0 Post(s)
    Hallo,

    ich bin gerade ein bisschen mit Guice am rumspielen und auf zwei Probleme gestoßen, die ich nicht so recht geknackt bekomme. Ich brechs mal auf den Kern der Problematik runter: Ich habe ein Spielobjekt, das zwei Spieler übergeben bekommt. Die Namen der Spieler werden zuvor gesetzt (beispielsweise in die GUI eingetragen)

    Java Code:
    1. public class Game {
    2.  
    3.     private Player p1;
    4.     private Player p2;
    5.  
    6.     public Game(Player p1, Player p2) {
    7.         this.p1 = p1;
    8.         this.p2 = p2;
    9.     }
    10. }
    Java Code:
    1. public class Player {
    2.     private String name;
    3.  
    4.     public Player(String name) {
    5.         this.name = name;
    6.     }
    7. }

    Wie bekomme ich hin, dass mir zwei unterschiedliche Playerobjekte gegeben werden? Providerklassen würden abhilfe schaffen, wenn die Spieler nicht noch einen zuvor gesetzten Namen brächten.

    Zweiter Fall: Das Spiel hat eine Liste von Spielphasen. Es gibt auch eine Phase-Klasse. Phasen unterscheiden sich durch ein Enum, das den Typ speichert sowie eine Liste von Events, die zu Rundenbeginn gefeuert werden.
    Java Code:
    1. public class Phase {
    2.     private PhaseType type;
    3.     private List<PhaseEvent> listEvents
    4.  
    5.     public Phase(PhaseType type, List<PhaseEvent> listEvents) {
    6.         this.type = type;
    7.         this.listEvents = listEvents;
    8.     }
    9. }

    Die Typen werden nach festen Regeln vergeben, sind also von vorn herein bekannt (genau wie die Events).

    Hoffe, hier kennt sich jemand bisschen mit Guice aus und kann mir helfen.

  2. #2
    Global Moderator Floppy Disc Avatar von Landei
    Registriert seit
    31.07.2013
    Ort
    Sandersdorf-Brehna
    Fachbeiträge
    990
    Genannt
    163 Post(s)
    Blog-Einträge
    27
    Bei den Spielern könnte die Named-Annotation helfen. Der Name muss natürlich im Guice-Modul auch entsprechend gesetzt werden: https://github.com/google/guice/wiki/BindingAnnotations

    Ungefähr so:
    Java Code:
    1.  
    2. bind(Player.class).annotatedWith(Names.named("player1")).toInstance(new Player("Alice"));
    3. bind(Player.class).annotatedWith(Names.named("player2")).toInstance(new Player("Bob"));

    Natürlich können die Namen auch später gesetzt werden, Hauptsache es ist durch die Annotation immer klar, welcher Spieler welcher ist.

    Beim zweiten bin ich mir nicht ganz sicher, was du meinst. Eventuell helfen Multibindings ( https://github.com/google/guice/wiki/Multibindings ) - die allerdings nur ein Set liefern. Du müsstest dir dann noch überlegen, wie du das dann geordnet bekommst.
    Geändert von Landei (01.04.2015 um 16:51 Uhr)

  3. #3
    Global Moderator Viertel Gigabyte Avatar von SlaterB
    Registriert seit
    06.08.2008
    Fachbeiträge
    2.695
    Genannt
    275 Post(s)
    bind(Player.class).annotatedWith(Names.named("player1")).toInstance(new Player("Alice"));
    äh, was für ein Framework ist das welches solchen Code evtl. erfordert, auf jeden Fall anscheinend zuläßt?
    für einen simplen Anfang mit zwei Player-Objekten?

    hoffentlich sind die sonstigen Vorteile gigantisch,
    aber eigentlich rechtfertigt nichts so eine Krücke im Programm..

    normale Programmierung mit Player p1 = new Player("Alice"); nicht aus den Augen verlieren!
    Hansa wird Meister

  4. #4
    Global Moderator Floppy Disc Avatar von Tomate_Salat
    Registriert seit
    30.07.2013
    Ort
    Durlach
    Fachbeiträge
    783
    Genannt
    150 Post(s)
    Blog-Einträge
    4
    Zitat Zitat von SlaterB Beitrag anzeigen
    äh, was für ein Framework ist das welches solchen Code evtl. erfordert, auf jeden Fall anscheinend zuläßt?
    Guice

    ---

    Aber ich würde meine Player-Klasse überdenken. Den Namen würde ich über einen Setter setzen und nicht unbedingt über den Konstruktor. Dann würde ich auch versuchen auf das "toInstance" zu verzichten, sonste nimmst du dir die Möglichkeit, dir Abhängigkeiten injecten zu lassen. Wenn du das berücksichtigst, dann könnte deine "Guice-Config" dafür so aussehen:

    Java Code:
    1. bind(Player.class).annotatedWith(Names.named("player1")).asEagerSingleton();
    2. bind(Player.class).annotatedWith(Names.named("player2")).asEagerSingleton();
    byte-welt.net - das Forum von Programmierern für Programmierer

    Naming Conventions
    Guice: Zwei Probleme

    JMapper | Instant Note (App)

  5. #5
    User Viertel Megabyte
    Registriert seit
    30.07.2013
    Fachbeiträge
    302
    Genannt
    73 Post(s)
    Moin,

    ich verstehe seine Frage so das er eigentlich AssistedInject sucht.

    Gruß
    Fancy

  6. #6
    Global Moderator Floppy Disc
    Registriert seit
    30.07.2013
    Fachbeiträge
    839
    Genannt
    109 Post(s)
    Factories finde ich eigentlich besser
    Maven is never completely installed

  7. #7
    User short Themenstarter
    Avatar von TheChemist
    Registriert seit
    07.08.2013
    Fachbeiträge
    25
    Genannt
    0 Post(s)
    Zitat Zitat von SlaterB Beitrag anzeigen
    bind(Player.class).annotatedWith(Names.named("player1")).toInstance(new Player("Alice"));
    äh, was für ein Framework ist das welches solchen Code evtl. erfordert, auf jeden Fall anscheinend zuläßt?
    für einen simplen Anfang mit zwei Player-Objekten?

    hoffentlich sind die sonstigen Vorteile gigantisch,
    aber eigentlich rechtfertigt nichts so eine Krücke im Programm..

    normale Programmierung mit Player p1 = new Player("Alice"); nicht aus den Augen verlieren!
    Das Beispiel war auf den Kern der Problematik reduziert. Zwei Objekte desselben Typs mit unterschiedlichen Attributen. Klar geht auch ein einfaches new Player(...). Beschäftigte mich aber gerade mit Dependency Injection und in dem Zusammenhang mit Guice.

    @Fancy AssistedInjects sehen schon mal ganz gut aus. Beantwortet mir zumindest mal die Frage, wie man Konstruktoren behandelt, die sowohl vom Injector bedient werden müssen, als auch selbst Attribute deklarieren.

    @Landei An die NamedAnnotations hab ich auch gedacht, das Binding von TS erscheint mir dann aber sinnvoller. Ein Ziel von Guice ist es doch, von der "händischen" Objekterzeugung abzusehen und das komplett des Modules zu überlassen oder? Allgemein verwirrt mich noch die Handhabe von Klassen, die zur Objekterzeugung z.B. Benutzereingaben übergeben bekommen. Oder ist es unüblich diese im Konstruktor zu setzen und bevorzugt durch Setter - wie von TS vorgeschlagen - zu setzen?

  8. #8
    Global Moderator Floppy Disc Avatar von Tomate_Salat
    Registriert seit
    30.07.2013
    Ort
    Durlach
    Fachbeiträge
    783
    Genannt
    150 Post(s)
    Blog-Einträge
    4
    Zitat Zitat von Fancy Beitrag anzeigen
    ich verstehe seine Frage so das er eigentlich AssistedInject sucht.
    Kommt drauf an, ob Player1 und Player2 wie Singletons behandelt werden sollen. Für denn Fall dass ja, dann bringt einem hier AssistedInjection nichts.

    Zitat Zitat von TheChemist Beitrag anzeigen
    Ein Ziel von Guice ist es doch, von der "händischen" Objekterzeugung abzusehen und das komplett des Modules zu überlassen oder? Allgemein verwirrt mich noch die Handhabe von Klassen, die zur Objekterzeugung z.B. Benutzereingaben übergeben bekommen. Oder ist es unüblich diese im Konstruktor zu setzen und bevorzugt durch Setter - wie von TS vorgeschlagen - zu setzen?
    Bei Konstruktorinjection muss man aufpassen. Man neigt imho gerade am Anfang dazu sich allen möglichen Scheiß darüber geben zu lassen. Ich würde dem Konstruktor aber wirklich nur das geben, was er zum erstellen des Objektes tatsächlich benötigt. Ist dies Abhängig von einer Benutzereingabe, dann wäre (wie Fancy schon gesagt hat) AssistedInjection die Lösung für dein Problem.
    byte-welt.net - das Forum von Programmierern für Programmierer

    Naming Conventions
    Guice: Zwei Probleme

    JMapper | Instant Note (App)

  9. #9
    User Viertel Megabyte
    Registriert seit
    30.07.2013
    Fachbeiträge
    302
    Genannt
    73 Post(s)
    Zwei Instanzen eines Singletons ist etwas wo ich wild mit den Armen wedelnd im Kreis renne. Vielleicht gibt es Anwendungen wo das wirklich sinnvoll ist, mir widerstrebt das aber irgendwie.

    Auch würde ich so viele Attribute unveränderlich machen wie es sinnvoll ist. Wenn der Name des Players später nicht mehr geändert werden soll, dann sollte imho die Player Klasse auch keinen Setter dazu anbieten.

    Konkret würde ich das obige etwa so schreiben:

    foobar.player.Player:
    Java Code:
    1. package foobar.player;
    2.  
    3.  
    4. public interface Player {
    5.  
    6. }

    foobar.player.PlayerFactory:
    Java Code:
    1. package foobar.player;
    2.  
    3.  
    4. public interface PlayerFactory {
    5.  
    6.     Player create(String name);
    7.  
    8. }

    foobar.player.PlayerImpl:
    Java Code:
    1. package foobar.player;
    2.  
    3.  
    4. import javax.inject.Inject;
    5.  
    6. import com.google.inject.assistedinject.Assisted;
    7.  
    8.  
    9. final class PlayerImpl implements Player {
    10.  
    11.     private final String name;
    12.  
    13.  
    14.     @Inject
    15.     private PlayerImpl(@Assisted final String name) {
    16.  
    17.         this.name = name;
    18.  
    19.     }
    20.  
    21.  
    22.     @Override
    23.     public String toString() {
    24.  
    25.         return "PlayerImpl [name=" + name + "]";
    26.  
    27.     }
    28.  
    29.  
    30. }

    foobar.player.PlayerModule:
    Java Code:
    1. package foobar.player;
    2.  
    3.  
    4. import com.google.inject.AbstractModule;
    5. import com.google.inject.assistedinject.FactoryModuleBuilder;
    6.  
    7.  
    8. public final class PlayerModule extends AbstractModule {
    9.  
    10.     @Override
    11.     protected void configure() {
    12.  
    13.         install(new FactoryModuleBuilder().implement(Player.class, PlayerImpl.class).build(PlayerFactory.class));
    14.  
    15.     }
    16.  
    17. }

    foobar.main.Main:
    Java Code:
    1. package foobar.main;
    2.  
    3.  
    4. import java.util.Scanner;
    5. import java.util.logging.Logger;
    6.  
    7. import javax.inject.Inject;
    8.  
    9. import com.google.inject.Guice;
    10.  
    11. import foobar.player.Player;
    12. import foobar.player.PlayerFactory;
    13. import foobar.player.PlayerModule;
    14.  
    15.  
    16. final class Main {
    17.  
    18.     private final Player player1;
    19.     private final Player player2;
    20.  
    21.  
    22.     @Inject
    23.     private Main(final Logger logger, final PlayerFactory playerFactory) {
    24.  
    25.         final Scanner scanner = new Scanner(System.in);
    26.  
    27.         System.out.println("Name of player one: ");
    28.         final String name1 = scanner.nextLine();
    29.         this.player1 = playerFactory.create(name1);
    30.  
    31.         System.out.println("Name of player two: ");
    32.         final String name2 = scanner.nextLine();
    33.         this.player2 = playerFactory.create(name2);
    34.  
    35.         scanner.close();
    36.  
    37.         logger.info("player1 = " + player1);
    38.         logger.info("player2 = " + player2);
    39.  
    40.     }
    41.  
    42.  
    43.     public static void main(final String[] args) {
    44.  
    45.         Guice.createInjector(new PlayerModule()).getInstance(Main.class);
    46.  
    47.     }
    48.  
    49. }

    Gruß
    Fancy

  10. #10
    User short Themenstarter
    Avatar von TheChemist
    Registriert seit
    07.08.2013
    Fachbeiträge
    25
    Genannt
    0 Post(s)
    @Fancy : Danke für das ausführliche Beispiel. Aber noch eine Frage zu dem Player Interface: In diesem (simplen) Beispiel erfüllt es keinen Zweck und auch in richtigen Anwendungen mag es nicht immer ein Interface für eine Klasse geben, die als Parameter übergeben wird. Gibt es also einen besonderen Grund warum du es hier doch aufgeführt hast?

    Ich habe mir dein Beispiel zum Anlass genommen, noch etwas vertrauter mit AssistedInjections zu werden und es ein bisschen ausgebaut:
    Java Code:
    1.  
    2. import java.util.Scanner;
    3. import java.util.logging.Logger;
    4.  
    5. import com.google.inject.Guice;
    6. import com.google.inject.Inject;
    7.  
    8. public class Main {
    9.  
    10.     public static void main(String[] args) {
    11.         Guice.createInjector(new GameModule()).getInstance(Main.class);
    12.     }
    13.  
    14.     @Inject
    15.     public Main(final Logger logger, final GameFactory gameFactory) {
    16.         final Scanner scanner = new Scanner(System.in);
    17.  
    18.         System.out.println("Name of player one: ");
    19.         final String playerName1 = scanner.nextLine();
    20.  
    21.         System.out.println("Name of player two: ");
    22.         final String playerName2 = scanner.nextLine();
    23.  
    24.         scanner.close();
    25.  
    26.         Game game = gameFactory.create(playerName1, playerName2);
    27.         game.start();
    28.  
    29.         logger.info("Game is now running");
    30.     }
    31. }
    Java Code:
    1.  
    2. import com.google.inject.assistedinject.Assisted;
    3.  
    4. public interface GameFactory {
    5.  
    6.     public Game create(@Assisted("playerName1") final String playerName1,
    7.             @Assisted("playerName2") final String playerName2);
    8.  
    9. }
    Java Code:
    1.  
    2. import com.google.inject.Inject;
    3. import com.google.inject.assistedinject.Assisted;
    4.  
    5. public class Game {
    6.  
    7.     private final Player p1;
    8.     private final Player p2;
    9.  
    10.     @Inject
    11.     public Game(final PlayerFactory playerFactory,
    12.             @Assisted("playerName1") final String playerName1,
    13.             @Assisted("playerName2") final String playerName2) {
    14.         this.p1 = playerFactory.create(playerName1);
    15.         this.p2 = playerFactory.create(playerName2);
    16.     }
    17.  
    18.     public void start() {
    19.         System.out.println("Game started!");
    20.         System.out.println("Player 1 = " + p1.toString());
    21.         System.out.println("Player 1 = " + p2.toString());
    22.     }
    23. }
    Java Code:
    1.  
    2. import com.google.inject.AbstractModule;
    3. import com.google.inject.assistedinject.FactoryModuleBuilder;
    4.  
    5. public class GameModule extends AbstractModule {
    6.  
    7.     @Override
    8.     protected void configure() {
    9.         install(new FactoryModuleBuilder().build(GameFactory.class));
    10.         install(new FactoryModuleBuilder().build(PlayerFactory.class));
    11.     }
    12.  
    13. }
    Java Code:
    1.  
    2. public interface PlayerFactory {
    3.  
    4.     public Player create(String name);
    5.  
    6. }
    Java Code:
    1.  
    2. import com.google.inject.Inject;
    3. import com.google.inject.assistedinject.Assisted;
    4.  
    5. public class Player {
    6.  
    7.     private final String name;
    8.  
    9.     @Inject
    10.     public Player(@Assisted final String name) {
    11.         this.name = name;
    12.     }
    13.  
    14.     @Override
    15.     public String toString() {
    16.         return name;
    17.     }
    18. }

  11. #11
    User Viertel Megabyte
    Registriert seit
    30.07.2013
    Fachbeiträge
    302
    Genannt
    73 Post(s)
    Sobald eine Klasse etwas sinnvolles macht, hat sie Methoden die aufgerufen werden können. Diese gehören dann in das Interface.

    Normalerweise lege ich in jedes Package mindestens ein öffentliches Interface, mindestens eine package-private Klasse mit privatem Konstruktor die das Interface implementiert und genau ein Guice-Modul (und ggf. die Factories). Dann ist das Package in sich abgeschlossen und bietet seine Funktionalität nur über sauber definierte Schnittstellen nach außen an. Implementierungsdetails können das Package so nicht verlassen.

    Gruß
    Fancy

  12. #12
    User short Themenstarter
    Avatar von TheChemist
    Registriert seit
    07.08.2013
    Fachbeiträge
    25
    Genannt
    0 Post(s)
    Okay, danke für die Erklärung. Ich konnte übrigens auch das zweite Problem, das ich oben etwas schlecht geschildert habe, mit Hilfe der AssistedInjections lösen. Insofern ist das Thema für mich erstmal erledigt

+ Antworten Thema als "offen" markieren

Direkt antworten Direkt antworten

In welcher Stadt befindet sich "Ground Zero"?

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Ähnliche Themen

  1. Zwei Views übereinanderlegen
    Von Zombiepriester im Forum Android
    Antworten: 27
    Letzter Beitrag: 17.03.2015, 11:08
  2. jarsplice exe startet zwei mal
    Von mymaksimus im Forum Allgemeine Themen
    Antworten: 2
    Letzter Beitrag: 27.12.2014, 11:29
  3. (Best Practice) Google Guice
    Von headnut im Forum Allgemeine Themen
    Antworten: 7
    Letzter Beitrag: 04.01.2014, 00:04
  4. Guice circular dependencies
    Von groggy im Forum Java-Grundlagen
    Antworten: 13
    Letzter Beitrag: 03.01.2014, 06:28
  5. Zwei XML-Dateien vergleichen
    Von Unregistriert im Forum Allgemeine Themen
    Antworten: 9
    Letzter Beitrag: 11.08.2013, 22:32

Stichworte

Berechtigungen

  • Neue Themen erstellen: Ja
  • Themen beantworten: Ja
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •