Menu
Coddy logo textTech

Pattern Decorator

Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 47 di 57.

Il pattern decorator avvolge un oggetto in un altro oggetto con la stessa interfaccia, che aggiunge qualcosa prima o dopo aver passato la chiamata. I decorator possono essere concatenati in qualsiasi ordine:

class Coffee
  def cost
    2.0
  end

  def description
    "coffee"
  end
end

class Milk
  def initialize(drink)
    @drink = drink
  end

  def cost
    @drink.cost + 0.5
  end

  def description
    "#{@drink.description}, milk"
  end
end

order = Milk.new(Milk.new(Coffee.new))
puts format("%s: %.2f", order.description, order.cost)

Output:

coffee, milk, milk: 3.00

Ogni decoratore memorizza l'oggetto avvolto e gli inoltra le chiamate, quindi una classe base condivisa può occuparsi di questa parte. Ogni decoratore concreto poi sovrascrive solo ciò che modifica:

class Coffee
  def cost
    2.0
  end

  def description
    "coffee"
  end
end

class Extra
  def initialize(drink)
    @drink = drink
  end

  def cost
    @drink.cost
  end

  def description
    @drink.description
  end
end

class Sugar < Extra
  def cost
    super + 0.2
  end

  def description
    super + ", sugar"
  end
end

order = Sugar.new(Coffee.new)
puts format("%s: %.2f", order.description, order.cost)

Output:

coffee, sugar: 2.20

La libreria standard SimpleDelegator (require 'delegate') inoltra all'oggetto wrapper ogni metodo che non definisce, mantenendo breti i decorator quando l'interfaccia è ampia:

require 'delegate'

class Loud < SimpleDelegator
  def to_s
    super.upcase + "!"
  end
end

text = Loud.new("hello")
puts text
puts text.size
puts text.start_with?("he")

Output:

HELLO!
5
true

I decoratori aggiungono comportamento ai singoli oggetti durante l’esecuzione e possono essere combinati liberamente. Con le sottoclassi, ogni combinazione, come MilkSugarCoffee, richiederebbe una classe propria:

Sugar.new(Milk.new(Coffee.new))      # qualsiasi combinazione, in qualsiasi ordine
Whip.new(Sugar.new(Coffee.new))

# con sottoclassi: MilkCoffee, SugarCoffee, MilkSugarCoffee, ...
challenge icon

Sfida

Facile

Completa i decoratori del caffè. Coffee costa 2.00 ed è descritto come coffee. Milk aggiunge 0.50 e , milk, Sugar aggiunge 0.20 e , sugar, e Whip aggiunge 0.70 e , whip. I tre decoratori condividono la classe base Extra, che memorizza la bevanda avvolta e inoltra cost e description; ogni sottoclasse usa super.

Ogni riga di input è un ordine, ad esempio milk sugar. Il codice fornito avvolge un nuovo Coffee nei decoratori in quest'ordine e stampa coffee, milk, sugar: 2.70.

Il tuo codice va in coffee.rb, extra.rb, milk.rb, sugar.rb e whip.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

require_relative 'coffee'
require_relative 'extra'
require_relative 'milk'
require_relative 'sugar'
require_relative 'whip'

# Código de entrada/salida proporcionado: mantenlo tal como está
input = []
while (line = gets)
  input << line.chomp
end
extras = { "milk" => Milk, "sugar" => Sugar, "whip" => Whip }
input.each do |line|
  drink = line.split.reduce(Coffee.new) { |d, name| extras[name].new(d) }
  puts format("%s: %.2f", drink.description, drink.cost)
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