Archives par étiquette : adapter

Ruby: design pattern Adapter

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