Eine Decorator Implementierung

Wenn es um eine konkrete Implementierung des Decorator Entwurfsmusters geht, gibt es in Ruby entsprechende Gems dafür. Meistens wird Draper verwendet, wobei es sich dabei genau genommen um eine Presenter Implementierung handelt.
Allerdings ist dessen gesamter Komfort meistens nicht notwendig. Stattdessen bietet Ruby mit der Klasse SimpleDelegator ein adäquates Werkzeug für eine einfache Decorator Implementierung.
Der Einfachheit halber, basiert das folgende Beispiel auf ein Ruby on Rails Projekt. Es geht dabei um Produkte:

rail$ rails g model Product serial:string sold_at:datetime && rake db:migrate

Jedes Produkt hat eine Seriennummer und ein Verkaufsdatum. An dem Verkaufsdatum hängt die zu gewährleistende Garantie von 6 Monaten.

class Product < ActiveRecord::Base
  WARRANTY_MONTHS = 6.months
  validates :serial, presence: true

  def warranty?
    return true if sold_at.nil?
    sold_at < WARRANTY_MONTHS.ago
  end
end

Natürlich steigt im Laufe der Entwicklung der Umfang der Geschäftslogik im Modell. Daher lohnt es sich, rechtzeitig entsprechende Logik auszulagern, erst Recht, wenn sie nur in einem bestimmten Kontext gebraucht wird.
Das Decorator Entwurfsmuster hilft, Klassen schlank zu halten.
Die Implementierung des ProduktDecorators und das schlanke Product Modell:

class ProductDecorator < SimpleDelegator
  WARRANTY_MONTHS = 6.months

  def warranty?
    return true if sold_at.nil?
    sold_at < WARRANTY_MONTHS.ago
  end

end

class Product < ActiveRecord::Base
  validates :serial, presence: true
end

und deren Verwendung:

product = Product.create serial: '123'
product_decorator = ProductDecorator.new product
product_decorator.serial # => "123"
product_decorator.warranty? # => true
product_decorator.sold_at = 7.month.ago
product_decorator.warranty? # => false
product_decorator.save

Eine klare Aufteilung: Product ist verantwortlich für die Persistierung und ProductDecorator enthält Geschäftslogik.
Lediglich der Zugriff auf Klassenmethoden des dekorierten Objektes sieht etwas ungünstig aus:

product_decorator = ProductDecorator.new Product.first
product_decorator.__getobj__ # => #<Product id: 1, serial: "123", ...>
product_decorator.__getobj__.class.name # => "Product"

Zwar ist der Zugriff auf das an den Decorator übergebene Objekt über SimpleDelegator#getobj möglich, aber das kann komfortabler gestaltet werden. Damit alle Dekorateure davon profitieren, bietet es sich an, entsprechende Methoden in eine SimpleDecorator Klasse rauszuziehen, zumal dann bei Ableitung der Zweck eindeutig wird:

class SimpleDecorator < SimpleDelegator
  alias_method :model, :__getobj__

  delegate :class, to: :model, prefix: true
end

class ProductDecorator < SimpleDecorator
  WARRANTY_MONTHS = 6.months

  def warranty?
    return true if sold_at.nil?
    sold_at < WARRANTY_MONTHS.ago
  end
end

Allein der Alias model auf __getobj__ und das Delegieren von class an das Objekt (model) erhöht die Lesbarkeit enorm:

product_decorator = ProductDecorator.new Product.first
product_decorator.model # => #<Product id: 1, serial: "123", ...>
product_decorator.model_class.name  # => "Product"