Adapt or die!
Le design pattern Adapter (ou Adaptateur en bon français) a déjà été évoqué ici-même il y a quelques années, aussi vous laisserai-je le plaisir d’aller y voir les détails d’implémentation si toutefois le code proposé ici ne vous parlait pas immédiatement !
Rafraîchissons-nous la mémoire
L’exemple est rigoureusement le même, si l’on excepte les particularités dues au langage Ruby (pas de classe abstraite, pas d’interface), mais je vais en rappeler les contours: nous avons un inspecteur du permis de conduire qui fait faire les mêmes manœuvres à tous ses candidats. L’ennui est que ces manœuvres ne s’effectuent pas de la même façon selon que l’on conduise un bateau à voile, à moteur, une voiture, une moto etc. Ainsi, notre inspecteur, qui manifestement n’a pas très envie de changer ses pratiques, va travailler avec des adaptateurs et non plus directement avec les classes feuilles de l’arbre matérialisant la chaîne d’héritage. Il n’y verra que du feu car ce sont les adaptateurs qui feront le travail à sa place !
Allez, en voiture !
class InspecteurPermisConduire def initialize(conducteur) @candidat = conducteur end def changerCandidat(conducteur) @candidat = conducteur end def fairePasserExamen @candidat.demarrer @candidat.accelerer @candidat.tournerDroite @candidat.accelerer @candidat.tournerGauche @candidat.ralentir @candidat.reculer @candidat.immobiliser end private attr_reader :candidat end class Conducteur def initialize(conducteur) raise "Impossible d'instancier la classe Conducteur" end def demarrer raise NotImplementedError end def tournerGauche raise NotImplementedError end def tournerDroite raise NotImplementedError end def accelerer raise NotImplementedError end def ralentir raise NotImplementedError end def reculer raise NotImplementedError end def immobiliser raise NotImplementedError end end class Automobiliste def demarrer puts "tourner la clé de contact ou mettre la carte" end def tournerGauche puts "tourner le volant vers la gauche" end def tournerDroite puts "tourner le volant vers la droite" end def accelerer puts "appuyer sur la pédale d'accélération" end def ralentir puts "relâcher la pédale d'accélération et/ou " + "appuyer sur la pédale de frein" end def reculer puts "passer la marche arrière et accélérer" end def immobiliser puts "mettre le frein à main" end end class Navigateur def initialize raise "Impossible d'instancier la classe abstraite Navigateur" end def demarrer raise NotImplementedError end def reculer raise NotImplementedError end def tournerBabord raise NotImplementedError end def tournerTribord raise NotImplementedError end def accelerer raise NotImplementedError end def ralentir raise NotImplementedError end def jeterAncre raise NotImplementedError end end class Marin def initialize raise "Impossible d'instancier la classe abstraite Marin" end # méthode commune à tous les marins def jeterAncre puts "jeter l'ancre à la mer" end end class MarinVoile < Marin def initialize # vide mais on peut imaginer de la logique ici end def demarrer puts "Cette fonctionnalité n'est pas disponible" end def tournerBabord puts "diriger les voiles et la barre pour aller à babord" end def tournerTribord puts "diriger les voiles et la barre pour aller à tribord" end def accelerer puts "positionner les voiles et déterminer l'allure" end def ralentir puts "positionner les voiles et déterminer l'allure" end def reculer puts "positionner les voiles et manœuvrer pour reculer" end end class MarinMoteur < Marin def initialize # vide mais on peut imaginer de la logique ici end def demarrer puts "démarrer le moteur" end def tournerBabord puts "manoeuvrer la barre ou le volant pour aller à babord" end def tournerTribord puts "manoeuvrer la barre ou le volant pour aller à tribord" end def accelerer puts "augmenter la vitesse du moteur" end def ralentir puts "dimininuer la vitesse du moteur ou le couper" end def reculer puts "passer la marche arrière" end end class AdaptateurMarin def initialize(marin) @marin = marin end def demarrer @marin.demarrer end def tournerGauche @marin.tournerBabord end def tournerDroite @marin.tournerTribord end def accelerer @marin.accelerer end def ralentir @marin.ralentir end def reculer @marin.reculer end def immobiliser @marin.jeterAncre end private attr_reader :marin end puts "AUTOMOBILISTE" inspecteur = InspecteurPermisConduire.new(Automobiliste.new) inspecteur.fairePasserExamen puts "MARIN MOTEUR" adaptateur = AdaptateurMarin.new(MarinMoteur.new) inspecteur = InspecteurPermisConduire.new(adaptateur) inspecteur.fairePasserExamen puts "MARIN VOILE" adaptateur = AdaptateurMarin.new(MarinVoile.new) inspecteur.changerCandidat(adaptateur) inspecteur.fairePasserExamen