Padrão Decorator
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 47 de 57.
O padrão decorator envolve um objeto em outro objeto com a mesma interface, que adiciona algo antes ou depois de encaminhar a chamada. Os decorators podem ser empilhados em qualquer ordem:
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)Saída:
coffee, milk, milk: 3.00Cada decorador armazena o objeto encapsulado e encaminha as chamadas para ele, portanto uma classe base compartilhada pode conter essa parte. Cada decorador concreto então sobrescreve apenas o que altera:
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)Saída:
coffee, sugar: 2.20A biblioteca padrão SimpleDelegator (require 'delegate') encaminha todos os métodos que não define para o objeto encapsulado, o que mantém os decoradores curtos quando a interface é grande:
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")Saída:
HELLO!
5
trueDecoradores adicionam comportamento a objetos individuais em tempo de execução e podem ser combinados livremente. Com subclasses, cada combinação, como MilkSugarCoffee, precisaria de uma classe própria:
Sugar.new(Milk.new(Coffee.new)) # qualquer combinação, qualquer ordem
Whip.new(Sugar.new(Coffee.new))
# com subclasses: MilkCoffee, SugarCoffee, MilkSugarCoffee, ...Desafio
FácilComplete os decoradores de café. Coffee custa 2.00 e é descrito como coffee. Milk adiciona 0.50 e , milk, Sugar adiciona 0.20 e , sugar, e Whip adiciona 0.70 e , whip. Os três decoradores compartilham a classe-base Extra, que armazena a bebida envolvida e encaminha cost e description; cada subclasse usa super.
Cada linha de entrada é um pedido, como milk sugar. O código fornecido envolve um novo Coffee nos decoradores nessa ordem e imprime coffee, milk, sugar: 2.70.
Seu código deve estar em coffee.rb, extra.rb, milk.rb, sugar.rb e whip.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'coffee'
require_relative 'extra'
require_relative 'milk'
require_relative 'sugar'
require_relative 'whip'
# Código de entrada/saída fornecido: mantenha-o 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
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação orientada a objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesVariáveis de InstânciaMétodos e selfto_s e inspectRevisão - Cartão da Biblioteca4Encapsulamento
Métodos privadosMétodos protegidosSetters privadosProtegendo o estadoRevisão - Máquina de venda automática7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMétodos Abstratoscase e ClassesRevisão - Métodos de Pagamento2Acessores e self
Leitores e GravadoresSetters Personalizadosself nos MétodosIdentidade e IgualdadeRecapitulação - Lista de Contatos5Herança
SubclassesSobrescrita de métodosChamando superis_a? e ancestraisRevisão - Folha de pagamento da equipe8Métodos Especiais
Igualdade e hashMétodos de OperadoresIndexação e AdiçãoColeções PersonalizadasRevisão - Frações11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de Ruby online