Pattern Builder
Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 48 di 57.
Il pattern builder crea un oggetto complesso passo dopo passo. Ogni passaggio è un metodo che memorizza una scelta e restituisce il builder, così i passaggi si concatenano; build controlla le scelte e restituisce l'oggetto completato:
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").buildOutput:
large pizza with cheese, hamPoiché il builder crea l'oggetto solo in build, può verificare l'intera combinazione in una volta sola, ad esempio una parte obbligatoria o due opzioni che non possono essere usate insieme:
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
endOutput:
ticket for seat B7
standing ticket
seat and standing exclude each otherUna forma comune in Ruby passa il builder a un blocco. Il metodo di classe crea il builder, lo passa a yield e chiama build alla fine:
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 mailOutput:
To: ada@x.io
Subject: Hi
Hello Ada,
see you soon.Per una manciata di valori facoltativi, spesso bastano gli argomenti con parole chiave e valori predefiniti di Ruby. Un builder è utile quando alcune parti possono ripetersi, l’ordine è importante o la combinazione va verificata prima che l’oggetto esista:
Pizza.new(size: "large", crust: "thin") # poche opzioni: parole chiave
Query.new.from("users").where("age > 18").where("active = 1").limit(10).to_sSfida
FacileCompleta PizzaBuilder e Pizza. I passaggi del builder size(value), crust(value) e topping(name) (ripetibile) restituiscono il builder. build solleva ArgumentError con size is required se non è stata specificata alcuna dimensione, usa la crosta classic se non ne è stata scelta una e restituisce una Pizza. Pizza#to_s restituisce large thin pizza with cheese, ham oppure small classic pizza with no toppings.
Ogni riga di input rappresenta un ordine, ad esempio size=large crust=thin topping=cheese topping=ham. Il codice fornito passa ogni parte al builder nell'ordine, concatenando le chiamate, e stampa la pizza o il messaggio di errore.
Il tuo codice va in pizza.rb e pizza_builder.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
require_relative 'pizza'
require_relative 'pizza_builder'
# Codice di input/output fornito: lascialo così com'è
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
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Classi e oggetti
Lavorare con i fileDefinire le classiVariabili d'istanzaMetodi e selfto_s e inspectRipasso - Tessera della biblioteca4Incapsulamento
Metodi privatiMetodi protettiSetter privatiProteggere lo statoRiepilogo - Distributore automatico7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMetodi astratticase e classiRiepilogo - Metodi di pagamento10Pattern di progettazione Parte 2
Delegazione con ForwardablePattern DecoratorPattern BuilderPattern State2Metodi di accesso e self
Metodi di lettura e scritturaSetter personalizzatiself nei metodiIdentità e uguaglianzaRiepilogo - Elenco contatti5Ereditarietà
SottoclassiRidefinizione dei metodiChiamare superis_a? e antenatiRiepilogo - Paghe del personale8Metodi speciali
Uguaglianza e hashMetodi degli operatoriIndicizzazione e appendCollezioni personalizzateRiepilogo - Frazioni11Progetto: Gestione della biblioteca
Libri e iscrittiPrendere in prestito i libriEsercitati da solo: Compilatore Ruby online