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
