Menu
Coddy logo textTech

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 possono concatenarsi; build controlla le scelte e restituisce l’oggetto completo:

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ò controllare l'intera combinazione in una volta sola, ad esempio una parte obbligatoria o due opzioni che non possono coesistere:

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, vi passa il controllo 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 un numero ridotto di valori facoltativi, gli argomenti con nome di Ruby con valori predefiniti sono spesso sufficienti. Un builder è utile quando alcune parti possono ripetersi, l’ordine è importante o è necessario verificare la combinazione prima che l’oggetto esista:

Pizza.new(size: "large", crust: "thin")          # few options: keywords

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 quando non è stata specificata una dimensione, usa la crosta classic quando 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 è un ordine, ad esempio size=large crust=thin topping=cheese topping=ham. Il codice fornito invia ogni parte al builder nell'ordine, concatenando le chiamate, e stampa la pizza o il messaggio di errore.

Il tuo codice va inserito 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'

# Código de entrada/salida proporcionado: déjalo tal como está
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