Menu
CoddyTech

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").build

Output:

large pizza with cheese, ham

Poiché 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
end

Output:

ticket for seat B7
standing ticket
seat and standing exclude each other

Una 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 mail

Output:

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_s
challenge icon

Sfida

Facile

Completa 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
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore Ruby online