IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Excès de génériques ?


Sujet :

Langage Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 41
    Points : 19
    Points
    19
    Par défaut Excès de génériques ?
    Bonjour,

    Je me demandais si suivant vos expériences, vous avez déjà été confrontés à utiliser les génériques de manière un peu excessive ? Si oui, pouvez-vous me dire si je ne suis pas tombé un peu dans l'excès avec mon enum. Histoire que vous ne expliquez un peu ce que j'ai essayé de faire: j'ai une classe Game qui utilise un Board et des Player qui exécute des Action sur le Board. Mes jeux de plateau vont tous hériter de cette classe, voilà pourquoi j'essaie d'être le plus générique possible et aussi pour ne pas devoir faire de cast à tout bout de champ dans les classes qui héritent.

    Maintenant, il est peut-être préférable d'en rester aux casts pour l'utilisation que j'en fait, qui reste, il est vrai, très basique car j'en fait tout au plus 1 fois dans 2-3 méthodes que doivent définir chacun des jeux. D'ailleurs, leur utilisation se répercute un peu partout. Une fois que j'en ai employé dans la classe Game, il a fallu que j'en introduise dans les classes Player et Board, ce qui devient un peu embêtant je trouve.

    Voilà pourquoi je viens demander votre avis d'expert

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    public enum GameState {
    	JOINING {
     
    		public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void joinPlayer(G game, Session session) {
    			game.insertPlayer(session);
    			if (game.getExpectedPlayerCount() == 0) {
    				game.setState(OPEN);
    			}
    		}
    	},
    	OPEN {
     
    		public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void playGame(G game) {
    			game.performGame();
    		}
     
    		public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void playTurn(G game) {
    			game.performTurn();
    		}
     
    		public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void makeAction(G game, Session session, A action) {
    			game.performAction(session, action);
    			if (game.isOver()) {
    				game.setState(ENDED);
    			}
    		}
     
    	},
    	ENDED {
    		public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void playGame(G game) {
    			/* Restart the game with the same players */
    			game.setState(OPEN);
    		}
    	};
     
    	public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void joinPlayer(G game, Session session) { /* Nothing to do */ }
    	public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void playGame(G game) { /* Nothing to do */ };
    	public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void playTurn(G game) { /* Nothing to do */ };
    	public <B extends Board, A extends Action<B>, P extends Player<B, A>, G extends Game<B, A, P>> void makeAction(G game, Session session, A action) { /* Nothing to do */ };
    Merci

  2. #2
    Membre éprouvé
    Inscrit en
    Mars 2006
    Messages
    848
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Mars 2006
    Messages : 848
    Points : 1 078
    Points
    1 078
    Par défaut
    Bonjour,

    il est en effet assez facile de tomber dans l'excès. Au premier coup d'oeil, je dirais volontiers que c'est ton cas.

    Quand cela m'arrive, je m'arrête et je prend un peu de recul pour analyser la situation.

    Il ne faut pas oublier que les génériques sont remplacés à la compilation par le type le plus général. Cela ne doit donc servir que pour assurer que tu ne fais pas n'importe quoi avant la compilation.

    Il faut aussi regarder quand le type générique est vraiment utilisé. Est-ce qu'il ne serait pas possible de passer par une méthode commune au type de base à cet endroit-là et donc de remplacer la généricité par une redéfinition de méthode?

    Les fois où je me suis retrouvé dans un cas excessif comme le tien, j'ai fini par enlever tous les génériques. Mais chaque cas est différent, tu auras peut être trouvé intéressant d'en garder un ou deux.

    Tiens-nous au courant, je suis intéressé de savoir si tu en auras gardé au final.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 41
    Points : 19
    Points
    19
    Par défaut
    Voilà,

    J'ai réussi à supprimer tous les génériques.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    public enum GameState {
    	JOINING {
     
    		public void joinPlayer(Game game, Session session) {
    			game.insertPlayer(session);
    			if (game.getExpectedPlayerCount() == 0) {
    				game.setState(OPEN);
    			}
    		}
    	},
    	OPEN {
     
    		public void playGame(Game game) {
    			game.performGame();
    		}
     
    		public void playTurn(Game game) {
    			game.performTurn();
    		}
     
    		public void makeAction(Game game, Session session, Action action) {
    			game.performAction(session, action);
    			if (game.isOver()) {
    				game.setState(ENDED);
    			}
    		}
     
    	},
    	ENDED {
    		public void playGame(Game game) {
    			/* Restart the game with the same players */
    			game.setState(OPEN);
    		}
    	};
     
    	public void joinPlayer(Game game, Session session) { /* Nothing to do */ }
    	public void playGame(Game game) { /* Nothing to do */ };
    	public void playTurn(Game game) { /* Nothing to do */ };
    	public void makeAction(Game game, Session session, Action action) { /* Nothing to do */ };
    }
    Comme dit précédemment, je fais un cast dans chacune des méthodes que je dois redéfinir dans les jeux. J'ai commencé par un jeu simple: le Tic tac toe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    public class TicTacToe extends Game {
    	private Map<Mark, Player> players = new HashMap<Mark, Player>();
     
    	public TicTacToe() {
    		super(new TicTacToeBoard(), 2);
    	}
     
    	@Override
    	public boolean isOver() {
    		TicTacToeBoard b = (TicTacToeBoard) getBoard();
    		return (getWinner() == null || b.getSquaresLeft() == 0);
    	}
     
    	@Override
    	protected Player createPlayer(Session session) {
    		Mark mark;
    		if (getExpectedPlayerCount() == 2) {
    			mark = Mark.X;
    		} else {
    			mark = Mark.O;
    		}
    		TicTacToePlayer player = new TicTacToePlayer(session, (TicTacToeBoard) getBoard(), Mark.X); 
    		players.put(mark, player);
    		return player;
    	}
     
    	@Override
    	protected void checkWinner() {
    		TicTacToeBoard b = (TicTacToeBoard) getBoard();
    		b.checkWinner();
    		Mark winnerMark = b.getWinner();
    		if (winnerMark != null) {
    			Player winner = players.get(winnerMark);
    			setWinner(winner);
    		}
    	}
    }
    En parlant de code générique, j'ai créé une classe Action dans la classe Game afin que pour chacun des jeux cette méthode puisse être utilisée et que seules les actions pouvaient différer. Seulement je n'arrive pas bien l'implémenter. Peut-être pouvez-vous m'aider ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void performAction(Session session, Action action) {
    	Player player = players.get(session);
    	player.makeAction(action);
    	checkWinner();
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public void performAction(Action action) {
    	action.executeOn(board);
    }
    Le problème de mon code est que je passe seulement le tableau à l'action cependant dans certain cas, j'ai besoin de données propre à un joueur, comme dans le Tic tac toe, de sa marque pour pouvoir marquer une case. J'espère ne pas trop avoir été flou :/

    Merci

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 553
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 553
    Points : 21 609
    Points
    21 609
    Par défaut
    Ben il faut simplement passer le contexte entier et pas juste le Board.

    Si tu veux mon avis, les classes Action ne devraient pas coder leur propre comportement. Un objet action devrait juste décrire ce que l'action "est" mais pas ce qu'elle "fait." "C'est l'action de jouer ici," "c'est l'action de passer son tour," "c'est l'action de promouvoir ce pion en reine" : le type d'action et ses éventuels paramètres.

    Effectivement réaliser les actions (et valider qu'elle a du sens et qu'on a le droit de la faire,) ça devrait être le travail d'une classe dédiée, genre "GameEngine" qui connaît le board en cours, quel joueur a joué en dernier et donc à qui c'est de jouer, les points, et tout.
    Tous les jeux auraient besoin d'une telle classe mais elle serait sensiblement différente d'un jeu à l'autre et n'aurait pas trop d'interface commune. Notamment chaque classe Action se ferait réaliser par une méthode de cette classe, spécifique à cette action.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 41
    Points : 19
    Points
    19
    Par défaut
    J'aurai peut-être du vous la montrer dès le début mais je pense que je possède déjà une classe comme celle que vous décrivez:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
     
    public abstract class Game {
    	private GameState state = GameState.JOINING;
    	private int expectedPlayerCount;
    	private Board board;
    	private Map<Session, Player> players = new HashMap<Session, Player>();
    	private Iterator<Player> iterator;
    	private Player winner;
     
    	public Game(Board board, int expectedPlayerCount) {
    		this.board = board;
    		this.expectedPlayerCount = expectedPlayerCount;
    	}
     
    	public void joinPlayer(Session session) {
    		state.joinPlayer(this, session);
    	}
     
    	public void insertPlayer(Session session) {
    		players.put(session, new Player(session, board));
    		--expectedPlayerCount;
    	}
     
    	public void playGame() {
    		state.playGame(this);
    	}
     
    	public void performGame() {
    		playRound();
    	}
     
    	public void playTurn() {
    		state.playTurn(this);
    	}
     
    	public void performTurn() {
    		if (iterator.hasNext()) {
    			Player player = iterator.next();
    			player.takeTurn();
    		} else {
    			playRound();
    		}
    	}
     
    	public void makeAction(Session session, Action action) {
    		state.makeAction(this, session, action);
    	}
     
    	public void performAction(Session session, Action action) {
    		Player player = players.get(session);
    		player.makeAction(action);
    		checkWinner();
    	};
     
    	public abstract boolean isOver();
     
    	public void setState(GameState state) {
    		this.state = state;
    	}
     
    	public int getExpectedPlayerCount() {
    		return expectedPlayerCount;
    	}
     
    	public Board getBoard() {
    		return board;
    	}
     
    	public Player getPlayer(Session session) {
    		return players.get(session);
    	}
     
    	public Player getWinner() {
    		return winner;
    	}
     
    	protected abstract void checkWinner();
     
    	protected void setWinner(Player winner) {
    		this.winner = winner;
    	}
     
    	private void playRound() {
    		iterator = players.values().iterator();
    	}
    }
    J'étais parti sur la même idée que vous mais il y avait une petite chose qui me gênait: admettons qu'il y ait plusieurs parties en cours de différents jeux. Lorsque je récupère une partie d'un certain joueur (au moyen de getGame(gameID) par exemple) pour appliquer une telle action sur le jeu, comment puis-je savoir de quel type de jeu il s'agit afin de caster l'objet Game retourné en un objet TicTacToe par exemple pour pouvoir utiliser une action propre à ce jeux ?

    Peut-être que je vois un problème là où il n'y en a pas ^

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 553
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 553
    Points : 21 609
    Points
    21 609
    Par défaut
    La classe que tu nous montre là ne sait pas du tout jouer au tic-tac-toe. On s'en servirait pour jouer au shogi que ce serait pareil.

    Pourtant, à un moment ou à un autre, il faudra bien qu'une classe sache jouer au tic-tac-toe. Et c'est une mauvaise idée de découper ça entre plein de classes Action qui savent mal voir ce que font les unes et les autres.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    41
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 41
    Points : 19
    Points
    19
    Par défaut
    La classe du TicTacToe est décrite dans mon deuxième message

    Je suis d'accord que ce soit une mauvaise idée que tout découper en plusieurs classes Action. Je vais essayer plusieurs solutions de mon côté, je pense m'être compliqué la tête pour rien :p Je reviendrai vers vous si j'ai encore des questions et merci de votre aide.

Discussions similaires

  1. Algorithmes génériques pour affichage de primitives 2D.
    Par Selenite dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 02/01/2005, 20h20
  2. [Generics] Classe générique
    Par norkius dans le forum Langage
    Réponses: 4
    Dernier message: 29/10/2004, 15h57
  3. classe date générique ?
    Par lili_bzh dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 07/09/2004, 10h59
  4. taille d'objet générique
    Par Heimdall dans le forum C
    Réponses: 7
    Dernier message: 01/07/2004, 18h00
  5. caractère générique utilisable dans strcmp
    Par barthelv dans le forum C
    Réponses: 9
    Dernier message: 01/08/2003, 16h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo