Gérer l’or en Java paraît simple tant qu’il ne s’agit que d’afficher un compteur. Dès qu’on ajoute des récompenses, des achats, des coffres ou une économie qui doit tenir dans la durée, le modèle de données devient décisif. Ici, je parle de l’or comme ressource, monnaie ou récompense dans un jeu ou une simulation, pas de l’opérateur logique. Je vais montrer comment représenter cette ressource proprement, quand utiliser un `enum`, quand préférer une classe, et comment éviter les bugs de solde négatif ou d’overflow.
Les choix qui évitent les bugs dans une économie d’or en Java
- Un enum sert à nommer un type d’or ou de ressource, pas à compter un solde.
- Pour un montant qui évolue, je privilégie une classe dédiée ou au minimum un `long`.
- Le seuil de sécurité passe vite à 2 147 483 647 avec `int`; au-delà, l’overflow devient réel.
- Si le jeu gère plusieurs ressources, `EnumMap` est souvent plus propre qu’une carte à clés texte.
- Les règles métier doivent vivre dans le modèle, pas dans l’interface.
Comprendre ce que représente vraiment cette ressource
Dans un jeu, l’or peut jouer plusieurs rôles : monnaie d’achat, score, récompense de combat, matériau d’amélioration ou simple variable de progression. Je commence toujours par séparer deux questions : est-ce un type ou une quantité ? Si la réponse change selon le moment du jeu, ce n’est pas le même objet métier. Un type se modélise comme une catégorie stable ; un solde évolue, se cumule, se dépense et doit être protégé contre les valeurs incohérentes.
Autrement dit, je ne traite pas de la même façon un coffre qui contient de l’or, une boutique qui en consomme et une interface qui affiche le total. C’est cette séparation qui évite ensuite les classes fourre-tout et les chaînes de caractères magiques. La décision de modélisation ouvre directement la question du bon outil Java, ce qui mène au choix entre `enum`, classe et simple compteur.
Choisir entre `enum`, classe et compteur numérique
Je vois souvent trois approches, et elles ne répondent pas au même besoin. La bonne solution dépend surtout du fait que l’or soit une catégorie fixe ou une valeur mutable.
| Approche | Quand l’utiliser | Avantages | Limites |
|---|---|---|---|
| Compteur simple `int` ou `long` | Solde unique, logique très simple, prototype rapide | Très lisible, peu de code, facile à afficher | Aucune validation métier, `int` sature vite |
| `enum` | Type de ressource, catégorie, rareté, tier fermé | Typage fort, évite les fautes de frappe, très clair | Ne gère pas les quantités qui bougent |
| Classe métier | Solde avec règles, achats, gains, plafonds, historique | Encapsulation, validation, extensible | Un peu plus de code, donc plus de structure |
Si vous gérez plusieurs ressources, `EnumMap
Construire un solde d’or robuste
Quand l’or circule, je préfère encapsuler le total dans une classe dédiée. L’idée est simple : la classe protège l’état, valide les entrées et centralise les règles de dépense.
public final class GoldWallet {
private long balance;
public GoldWallet(long initialBalance) {
if (initialBalance < 0) {
throw new IllegalArgumentException("Le solde initial ne peut pas être négatif.");
}
this.balance = initialBalance;
}
public long getBalance() {
return balance;
}
public void earn(long amount) {
if (amount < 0) {
throw new IllegalArgumentException("Le gain doit être positif.");
}
balance = Math.addExact(balance, amount);
}
public boolean spend(long amount) {
if (amount < 0) {
throw new IllegalArgumentException("La dépense doit être positive.");
}
if (amount > balance) {
return false;
}
balance -= amount;
return true;
}
}Je choisis `long` plutôt que `int` dès que l’économie peut grossir, parce que la limite de `int` est vite atteinte dans un jeu idle, une boucle de récompenses ou un simulateur économique. `Math.addExact` est utile ici : il fait échouer le calcul au lieu de laisser un débordement silencieux. Si votre jeu est multijoueur ou synchronisé réseau, cette logique doit idéalement vivre côté serveur, pas dans le client.
Avec cette base, les achats et les récompenses deviennent prévisibles. La question suivante est alors plus ciblée : quand un `enum` reste-t-il pertinent sans surcharger le design ?
Utiliser un `enum` quand l’or n’est qu’un type parmi d’autres
Un `enum` est utile si vous ne comptez pas des pièces, mais des types de ressources ou des tiers. En Java, c’est une très bonne réponse quand l’ensemble des valeurs est connu à la compilation et ne doit pas être étendu à la volée.
public enum ResourceType {
GOLD("Or", 1),
WOOD("Bois", 1),
IRON("Fer", 3);
private final String label;
private final int baseValue;
ResourceType(String label, int baseValue) {
this.label = label;
this.baseValue = baseValue;
}
public String getLabel() {
return label;
}
public int getBaseValue() {
return baseValue;
}
}Dans ce cas, un `EnumMap
C’est exactement ce mauvais mélange qui crée les systèmes fragiles, ce qui nous amène aux erreurs les plus fréquentes.
Éviter les erreurs qui cassent l’économie du jeu
- Confondre type et quantité : un `enum` pour dire “or” oui, un `enum` pour stocker 347 pièces non.
- Utiliser `int` par réflexe : au-delà de 2 147 483 647, vous exposez le jeu à un overflow discret.
- Autoriser les valeurs négatives : un solde ne devrait jamais devenir négatif par accident ; si une dette existe, elle mérite un modèle explicite.
- Dupliquer la logique dans l’interface : le bouton “Acheter” ne doit pas décider seul si l’opération est valide.
- Stocker des montants sous forme de texte : cela complique les calculs, la persistance et les tests.
Je teste toujours au moins trois cas : gain normal, dépense refusée faute de solde, et valeur extrême qui vérifie l’absence de débordement. Ce trio révèle vite les failles qui ne se voient pas dans une démo courte. Une fois ces garde-fous posés, on peut assembler un exemple complet sans alourdir la structure.
Assembler un exemple complet de récompense et d’achat
Pour un jeu simple, je sépare souvent trois responsabilités : la classe qui porte le solde, le service qui distribue les gains et l’écran qui affiche le résultat. Cette organisation reste légère, mais elle évite de mélanger aléatoire, règles métier et rendu.
import java.util.concurrent.ThreadLocalRandom;
public final class RewardService {
public long chestReward() {
return ThreadLocalRandom.current().nextLong(10, 31);
}
public void grantChestReward(GoldWallet wallet) {
wallet.earn(chestReward());
}
public boolean buyItem(GoldWallet wallet, long cost) {
return wallet.spend(cost);
}
}Utilisé ainsi, le flux est lisible :
GoldWallet wallet = new GoldWallet(100);
RewardService rewards = new RewardService();
rewards.grantChestReward(wallet);
boolean bought = rewards.buyItem(wallet, 75);Ce schéma est simple, mais il couvre déjà beaucoup de cas réels : récompense aléatoire, dépense contrôlée et solde persistable en base avec un type numérique compatible `BIGINT`. Si le projet grandit, on peut ajouter des événements, des logs de transactions ou des plafonds sans casser le cœur du modèle. La vraie discipline consiste maintenant à choisir ce qui mérite d’être généralisé et ce qui doit rester volontairement simple.
Ce que je recommande pour garder un système lisible en 2026
Si je devais livrer une version propre sans sur-ingénierie, je ferais trois choix : `long` pour le solde, `enum` pour les catégories fermées, et une classe métier pour toutes les opérations qui modifient l’or. Ce trio couvre la majorité des jeux et des simulateurs sans complexifier inutilement le code.
- Conservez la règle de solde dans la classe métier, pas dans le bouton ou l’écran.
- Si plusieurs ressources existent, regroupez-les avec `EnumMap` plutôt qu’avec des clés texte.
- Validez chaque entrée avant de modifier le solde, y compris les bonus et les remboursements.
- Pensez à la persistance dès le départ : un `BIGINT` en base évite les mauvaises surprises.
- Ajoutez des tests sur les frontières : 0, montant exact, montant trop élevé, valeur proche de la limite.
Au fond, la meilleure modélisation de l’or n’est pas la plus sophistiquée, c’est celle qui rend les règles du jeu évidentes à relire six mois plus tard. C’est ce qui permet d’ajouter des coffres, des boutiques ou une économie plus riche sans transformer le code en bricolage permanent.