J'ai déjà pensé à utiliser des classes générique puis les spécialiser avec des paramètres (il doit bien y avoir un tas de pattern géniaux) sauf
que j'ai besoin de minimum 1 classe par "espèce" (sous entendu ce que tu pourrais me proposer, donc la ça peut le faire) mais je dois nécessairement avoir
des classes différentes pour chacun de leur component (et au minimum de 3). C'est assez difficile par écrit d'expliquer mais si tu as un exemple connu
je pourrais regarder et voir si je peux m'en inspirer.
Je ne fouille pas assez dans les codes des autres pour trouver des exemples très connus. Mais à te lire, il me semble que tu pourrais utiliser le pattern strategy, une fois par type d'élément différent.
Quand j'ai essayé de résoudre le javaquarium, j'ai utilisé le pattern strategy un peu à ma sauce. En gros j'avais ça (reconstitution de mémoire, j'ai pas le code ici) :
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 | interface Reproduction {
public boolean isFemale (Fish thisFish);
public boolean canReproduce (Fish thisFish) ;
public boolean canReproduce (Fish thisFish, Fish anotherFish);
public Fish reproduce (Fish thisFish, Fish parthner);
public void update (Fish thisFish);
}
interface Eating {
public boolean isHungry (Fish thisfish) ;
public boolean canEat (Fish thisFish, Fish target);
public void eat (Fish thisFish, Fish target);
}
interface Life {
public boolean isAlive (Fish thisFish);
public void update (Fish thisFish);
}
class Fish {
final Reproduction reproduction;
final Eating eating;
final Life life;
public Fish (Reproduction r, Eating e, Life l) {
//...
}
//...
}
|
Dans une autre partie, j'avais ça :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | public static final Reproduction
NORMAL = new Reproduction(){
// Définition de la reproduction normale, i.e. seuls un mâle et une femelle de la même espèce peuvent se reproduire
},
OPPORTUNISTIC = new Reproduction(){
// Définition de la reproduction opportuniste, i.e. le poisson cible change de sexe juste au moment de l'accouplement si nécessaire
},
HALF_LIFE = new Reproduction(){
// Définition de la reproduction demi-vie, i.e. le poisson change de sexe à un âge prédéfini
};
// Même genre de truc pour la politique de gestion de la vie, et pour le régime alimentaire
``
Et puis encore ailleurs :
```java
class ClownFish extends Fish {
public ClownFish () {
super(OPPORTUNISTIC, MEAT_EATER, NORMAL_FISH_LIFE);
}
}
|
Avec un peu de recul et en lisant ce qu'on fait les autres, j'ai remarqué que j'avais fait des erreurs de conception et ai constaté plusieurs choses :
- Si les politiques n'étaient pas final, j'aurais eu la capacité de changer dynamiquement le comportement du poisson au cours de sa vie
- J'ai bien fait de ne pas faire des classes internes car sinon ça pouvait être difficile d'ajouter des politiques par la suite, hors programme principal, au cas où on a plus la main sur le code de Fish
- En fait la classe ClownFish et ses conseurs ne servent à rien, j'aurais dû faire un système de factory à la place
Pourquoi je raconte tout ça ? En fait, j'ai vaguement l'impression que les classes que tu veux construire dynamiquement, c'est dans le genre de ma classe ClownFish ci-dessus.
Tu peux bien sûr faire une sous-classe par combinaison de propriétés existantes, mais ce n'est pas flexible. Et effectivement dans ce mode de pensée, si tu veux donner à l'utilisateur le choix des propriétés, tu es obligé de créer des nouvelles classes dynamiquement.
Alors que si les propriétés que tu définis sous forme d'interfaces sont bien construites, tu n'as pas besoin. Tu instancies Fish directement, et tu passes seulement les bonnes propriétés; pas besoin de sous-classes dynamiques.
Tu as besoin d'un nouveau mode de reproduction, admettons que certains poissons peuvent être homosexuels ? pas de problème, une nouvelle instance de Reproduction fera l'affaire.
Et si à un moment donné tu veux ajouter un tout nouveau comportement pas encore envisageable à l'aide des interface que tu as déjà, la mort naturelle des poissons, ou la pousse des écailles par exemple, tu définis une nouvelle gamme de propriétés (une nouvelle interface) plutôt que des sous-classes.
Au final, tu n'utiliss que la classe Fish et c'est très flexible, tout le reste est défini dans des classes de comportements complètement séparées.
L'évolution suivante beaucoup plus généralisée de mon système, c'est l'entity component system (ECS). Je n'ai pas encore eu le courage de m'y atteler sérieusement moi-même, mais d'autres membres ont déjà commencé et partagé sur ce sujet. Une recherche ici même ou ailleurs pourrait t'être instructive.