Patron Builder
Fait partie de la section Programmation orientée objet du Journey Ruby de Coddy. Leçon 48 sur 57.
Le modèle builder crée un objet complexe étape par étape. Chaque étape est une méthode qui stocke un choix et renvoie le builder, ce qui permet d’enchaîner les étapes ; build vérifie les choix et renvoie l’objet terminé :
class Pizza
def initialize(size, toppings)
@size = size
@toppings = toppings
end
def to_s
"#{@size} pizza with #{@toppings.join(", ")}"
end
end
class PizzaBuilder
def initialize
@toppings = []
end
def size(value)
@size = value
self
end
def topping(name)
@toppings << name
self
end
def build
raise ArgumentError, "size is required" if @size.nil?
Pizza.new(@size, @toppings)
end
end
puts PizzaBuilder.new.size("large").topping("cheese").topping("ham").buildSortie :
large pizza with cheese, hamComme le builder ne crée l’objet que dans build, il peut vérifier toute la combinaison en une seule fois, par exemple la présence d’une partie obligatoire ou de deux options qui ne peuvent pas être utilisées ensemble :
class TicketBuilder
def seat(value)
@seat = value
self
end
def standing
@standing = true
self
end
def build
raise ArgumentError, "seat and standing exclude each other" if @seat && @standing
@standing ? "standing ticket" : "ticket for seat #{@seat || "any"}"
end
end
puts TicketBuilder.new.seat("B7").build
puts TicketBuilder.new.standing.build
begin
TicketBuilder.new.seat("A1").standing.build
rescue ArgumentError => e
puts e.message
endSortie :
ticket for seat B7
standing ticket
seat and standing exclude each otherUne forme courante en Ruby transmet le builder à un bloc. La méthode de classe crée le builder, lui cède l’exécution, puis appelle build à la fin :
class Email
attr_accessor :to, :subject, :lines
def self.compose
email = new
email.lines = []
yield email
email
end
def to_s
"To: #{to}\nSubject: #{subject}\n\n#{lines.join("\n")}"
end
end
mail = Email.compose do |e|
e.to = "ada@x.io"
e.subject = "Hi"
e.lines << "Hello Ada,"
e.lines << "see you soon."
end
puts mailSortie :
To: ada@x.io
Subject: Hi
Hello Ada,
see you soon.Pour une poignée de valeurs facultatives, les arguments nommés de Ruby avec des valeurs par défaut suffisent souvent. Un générateur devient utile lorsque certaines parties peuvent se répéter, que l’ordre est important ou que la combinaison doit être vérifiée avant que l’objet n’existe :
Pizza.new(size: "large", crust: "thin") # peu d'options : mots-clés
Query.new.from("users").where("age > 18").where("active = 1").limit(10).to_sDéfi
FacileComplétez PizzaBuilder et Pizza. Les étapes du générateur size(value), crust(value) et topping(name) (répétable) renvoient le générateur. build lève ArgumentError avec size is required lorsqu'aucune taille n'a été indiquée, utilise la croûte classic lorsqu'aucune n'a été choisie, et renvoie une Pizza. Pizza#to_s renvoie large thin pizza with cheese, ham ou small classic pizza with no toppings.
Chaque ligne d'entrée est une commande telle que size=large crust=thin topping=cheese topping=ham. Le code fourni envoie chaque élément au générateur dans l'ordre, par chaînage, et affiche la pizza ou le message d'erreur.
Votre code doit se trouver dans pizza.rb et pizza_builder.rb. main.rb contient le code d'entrée/sortie fourni et ne peut pas être modifié.
Essayez vous-même
require_relative 'pizza'
require_relative 'pizza_builder'
# Code d'entrée/sortie fourni : le garder tel quel
input = []
while (line = gets)
input << line.chomp
end
input.each do |line|
builder = line.split.reduce(PizzaBuilder.new) do |b, part|
step, value = part.split("=")
b.public_send(step, value)
end
begin
puts builder.build
rescue ArgumentError => e
puts e.message
end
end
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Classes et objets
Travailler avec des fichiersDéfinir des classesVariables d’instanceMéthodes et selfto_s et inspectRécapitulatif - Carte de bibliothèque4Encapsulation
Méthodes privéesMéthodes protégéesSetters privésProtéger l’étatRécapitulatif - Distributeur automatique7Polymorphisme et typage canard
PolymorphismeTypage canardMéthodes abstraitesCas et classesRécapitulatif - méthodes de paiement10Patrons de conception – Partie 2
Délégation avec ForwardablePatron DécorateurPatron BuilderPatron État2Accesseurs et self
Lecteurs et écrivainsSetters personnalisésself dans les méthodesIdentité et égalitéRécapitulatif - Liste de contacts5Héritage
Sous-classesRedéfinition des méthodesAppeler superis_a? et ancêtresRécapitulatif - Paie du personnel8Méthodes spéciales
Égalité et hachageMéthodes d’opérateursIndexation et ajoutCollections personnaliséesRécapitulatif - Fractions11Projet : Gestion de bibliothèque
Livres et membresEmprunter des livresEntraînez-vous par vous-même : Compilateur Ruby en ligne