Patrón Decorator
Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 47 de 57.
El patrón decorador envuelve un objeto en otro objeto con la misma interfaz, que añade algo antes o después de pasar la llamada. Los decoradores se pueden apilar en cualquier orden:
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)Salida:
coffee, milk, milk: 3.00Cada decorador almacena el objeto envuelto y delega en él, por lo que una clase base compartida puede encargarse de esa parte. Después, cada decorador concreto sobrescribe únicamente lo que cambia:
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)Salida:
coffee, sugar: 2.20La biblioteca estándar SimpleDelegator (require 'delegate') reenvía todos los métodos que no define al objeto envuelto, lo que permite mantener breves los decoradores cuando la interfaz es 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")Salida:
HELLO!
5
trueLos decoradores añaden comportamiento a objetos individuales en tiempo de ejecución y se pueden combinar libremente. Con subclases, cada combinación, como MilkSugarCoffee, necesitaría su propia clase:
Sugar.new(Milk.new(Coffee.new)) # cualquier combinación, cualquier orden
Whip.new(Sugar.new(Coffee.new))
# con subclases: MilkCoffee, SugarCoffee, MilkSugarCoffee, ...Desafío
FácilCompleta los decoradores de café. Coffee cuesta 2.00 y se describe como coffee. Milk añade 0.50 y , milk, Sugar añade 0.20 y , sugar, y Whip añade 0.70 y , whip. Los tres decoradores comparten la clase base Extra, que almacena la bebida envuelta y reenvía cost y description; cada subclase usa super.
Cada línea de entrada es un pedido, como milk sugar. El código proporcionado envuelve un nuevo Coffee en los decoradores en ese orden e imprime coffee, milk, sugar: 2.70.
Tu código va en coffee.rb, extra.rb, milk.rb, sugar.rb y whip.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
require_relative 'coffee'
require_relative 'extra'
require_relative 'milk'
require_relative 'sugar'
require_relative 'whip'
# Código de entrada/salida suministrado: déjalo 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
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesVariables de instanciaMétodos y selfto_s e inspectRepaso: tarjeta de biblioteca4Encapsulación
Métodos privadosMétodos protegidosAsignadores privadosProtección del estadoRepaso: máquina expendedora7Polimorfismo y tipado pato
PolimorfismoTipado patoMétodos abstractoscase y clasesRepaso: métodos de pago2Accesores y self
Lectores y escritoresSetters personalizadosself en los métodosIdentidad e igualdadRepaso: lista de contactos5Herencia
SubclasesSobrescritura de métodosLlamar a superis_a? y ancestrosRepaso - Nómina del personal8Métodos especiales
Igualdad y hashMétodos de operadoresIndexación y adiciónColecciones personalizadasRepaso: fracciones11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de Ruby online