Dekorator przyjmuje w konstruktorze obiekt i dodaje do niego nowe zachowania. Przykładem dekoratora jest Presenter – klasa dodająca do obiektu możliwość zaprezentowania się, np. w postaci sformatowanego Stringa, XML-a czy JSON-a. Na wroc_lover.rb Piotr Szotkowski pokazał bardzo fajny sposób tworzenia dekoratorów z użyciem SimpleDelegator. Zysk polega na uniknięciu boilerplate kodu – wszystkie metody dostępne na wejściowym obiekcie stają się dostępne bezpośrednio w dekoratorze.
require 'delegate'
class Address
# extend with your favourite persistence solution or:
attr_accessor :street, :postcode, :city, :country
def initialize args = {}
args.each { |key, value| send "#{key}=", value }
end
end
class PolishAddress < SimpleDelegator
def initialize address
super address
end
def formatted
[street, "#{postcode} #{city}", country].join "\n"
end
end
Czyli mamy i ładnie (SRP), i zwięźle (no boilerplate code). Jeśli natomiast potrzebujemy Presentera bazującego na więcej niż jednym obiekcie, z pomocą przyjdzie mixin Forwardable, również z stdlib:
require 'forwardable'
class PolishEnvelopeAddress
extend Forwardable
def initialize args
@person = args.fetch :person, Person.new
@address = args.fetch :address, Address.new
end
def_delegators :@person, :given_names, :surname
def_delegators :@address, :street, :postcode, :city, :country
def formatted
["Sz.P. #{given_names} #{surname}",
street, "#{postcode} #{city}", country].join "\n"
end
end