Archives par étiquette : builder

Ruby: design pattern Builder

Veuillez monter !

Le design pattern Builder, appelé « Monteur » en français est un design pattern de création dont le but est d’aider à créer des objets complexes. Pour cela, il intègre une classe appelée directeur qui contrôle l’algorithme de construction.

Composants du design pattern Builder

Les composants participant à ce pattern sont les suivants:

  • Le directeur, qui prend en composition un monteur
  • Une abstraction pour les monteurs
  • Des monteurs concrets
  • Des parties
  • Des produits (la cible finale !)

Dans l’exemple qui suit, nous aurons:

  • Des monteurs de camions et de voitures
  • Des produits : Camion et Voiture
  • Des parties : porte, moteur, roue
  • Un directeur qui orchestre la construction de tout ça

Nos abstractions seront des classes abstraites simulées (pas d’interface en Ruby, ni de classes abstraites stricto sensu).

class Piece
  def donnerNom
    raise "Impossible d'instancier la classe ProduitEntretien"
  end
end

class PorteCamion < Piece
  def donnerNom
    "Porte de camion"
  end
end

class PorteVoiture < Piece
  def donnerNom
    "Porte de voiture"
  end
end

class RoueCamion < Piece
  def donnerNom
    "Roue de camion"
  end
end

class RoueVoiture < Piece
  def donnerNom
    "Roue de voiture"
  end
end

class MoteurVoiture < Piece
  def donnerNom
    "Moteur de voiture"
  end
end

class MoteurCamion < Piece
  def donnerNom
    "Moteur de camion"
  end
end

class Vehicule

  def initialize
    @configuration = {}
  end

  def ajouter_piece(nom, piece)
    @configuration[nom] = piece
  end

  protected

  attr_reader :configuration
end

class Camion < Vehicule
end

class Voiture < Vehicule
end

class Directeur

  def initialize (monteur)
    @monteur = monteur
  end

  def monter
    @monteur.creer_vehicule
    @monteur.poser_portes
    @monteur.poser_moteur
    @monteur.poser_roues
    @monteur.peindre
  end

  private

  attr_reader :monteur
end

class Monteur

  def initialize
    raise "Impossible d'instancier la classe abstraite Monteur"
  end

  def creer_vehicule
    raise NotImplementedError
  end

  def poser_portes
    raise NotImplementedError
  end

  def poser_moteur
    raise NotImplementedError
  end

  def poser_roues
    raise NotImplementedError
  end

  def peindre
    raise NotImplementedError
  end

  def donner_vehicule
    raise NotImplementedError
  end
end

class MonteurVoitures < Monteur

  def initialize(options)
    @options = options
  end

  def creer_vehicule
    @voiture = Voiture.new
  end

  def poser_portes
    @voiture.ajouter_piece('porte AVG', PorteVoiture.new)
    @voiture.ajouter_piece('porte AVD', PorteVoiture.new)
    @voiture.ajouter_piece('porte arrière', PorteVoiture.new)

    if 3 < @options['nb_portes']
      @voiture.ajouter_piece('porte ARG', PorteVoiture.new)
      @voiture.ajouter_piece('porte ARD', PorteVoiture.new)
    end
  end

  def poser_moteur
    @voiture.ajouter_piece('moteur', MoteurVoiture.new)
  end

  def poser_roues
    @voiture.ajouter_piece('roue AVG', RoueVoiture.new)
    @voiture.ajouter_piece('roue AVD', RoueVoiture.new)
    @voiture.ajouter_piece('roue ARG', RoueVoiture.new)
    @voiture.ajouter_piece('roue ARD', RoueVoiture.new)
  end

  def peindre
    puts "Je peins la voiture en " + @options['couleur_peinture']
  end

  def donner_vehicule
    @voiture
  end

  private

  attr_reader :voiture, :options
end


class MonteurCamions < Monteur

  def initialize(options)
    @options = options
  end

  def creer_vehicule
    @camion = Camion.new
  end

  def poser_portes
    @camion.ajouter_piece('porte AVG', PorteCamion.new)
    @camion.ajouter_piece('porte AVD', PorteCamion.new)
  end

  def poser_moteur
    @camion.ajouter_piece('moteur', MoteurCamion.new)
  end

  def poser_roues
    @camion.ajouter_piece('roue AVG', RoueCamion.new)
    @camion.ajouter_piece('roue AVD', RoueCamion.new)
    @camion.ajouter_piece('roue ARG', RoueCamion.new)
    @camion.ajouter_piece('roue ARD', RoueCamion.new)
  end

  def peindre
    puts "Je peins le camion en " + @options['couleur_peinture']
  end

  def donner_vehicule
    @camion
  end

  private

  attr_reader :camion, :options
end


monteur_voitures = MonteurVoitures.new({'nb_portes' => 5, 'couleur_peinture' => 'rouge'})
monteur_camions = MonteurCamions.new({'couleur_peinture' => 'bleu'})

[monteur_voitures, monteur_camions].each do |monteur|
  directeur = Directeur.new(monteur)
  directeur.monter
  vehicule = monteur.donner_vehicule
end