Un exemple de polymorphisme en situation réelle
J’écris en ce moment un émulateur pour Chip-8, en Ruby. Dans les outils que j’écris à coté il y a un désassembleur de code Chip-8. Dans ce désassembleur il y a un bel exemple de polymorphisme.
Un peu de contexte
La classe Opcode permet de faire la correspondance entre un opcode Chip-8 et une ligne de code assembleur. Un opcode Chip-8 est toujours représenté par un nombre hexadécimal de 4 chiffres.
Voici quelques exemples d’opcodes et leur correspondance en assembleur :
Opcode | Assembleur | Remarque
-------|-------------|---------
2a00 | CALL a00 |
7012 | ADD V0, 12 | V0 est un registre
a22e | LOAD I, 22e | I est un registre
On pourra remarquer (même si ça n’est pas ultra visible avec seulement trois
exemples) que c’est le premier chiffre (ici 2
, 7
et a
) qui décide du
type d’instruction.
De 0
à f
, on a donc 16 types possibles, ce qui donne ce genre de code :
De plus, certains type d’instruction sont partagés en sous type, selon le quatrième chiffre, ou bien selon les troisième et quatrième, ça dépend. Comme toujours, on se retrouve à devoir gérer des cas particuliers, et le code ressemble rapidement à la monstruosité qui suit :
C’est pas bon, hein ? Pour arranger ça, rien de tel qu’un peu de polymorphisme. La classe Opcode va donc se contenter de ceci :
Vous devinez que c’est maintenant dans une nouvelle classe Assembly
que sont géré les différentes
instructions et sous instructions :
Et bien non, elles sont gérées chacune dans sa classe respective, à savoir
Asm0
, Asm1
, Asm2
, et cetera jusqu’à Asmf
. Voici un exemple :
Chacune des classes Asm0
à Asmf
hérite de AsmBase
qui définit le
comportement commun (nnn, kk, x et y sont simplement des conventions de nommage en
assembleur Chip-8) :
C’est un cas classique d’utilisation du polymorphisme. On troque un long switch/case (virtuellement infini) pour plusieurs petites classes simples. Le système est toujours aussi complexe dans son ensemble, mais sa maintenance est maintenant plus facile.